Libraryless. Click here for Pure Java version (21298L/156K).
!7 sclass VidFile { File file; double length = -1; transient float[] profile; transient L<DoubleRange> ranges; S id() { ret md5FromFilePathSizeAndDate(file); } File audioFile() { ret prepareCacheProgramFile("preview-" + id() + ".wav"); } } module AJCBatch > DynObjectTable<VidFile> { S outputFile; int volumeThresholdPercent = 15; S minSilence = "0.2", leadIn = "0.2", leadOut = "0.2"; transient double profileSamplingInterval = 0.05; // 50 ms transient int audioWindowSize = iround(profileSamplingInterval*16000); S originalLength, cutLength; transient ReliableSingleThread rstScan = dm_rst(this, r scan); visualize { JComponent sup = super.visualize(); ret centerAndSouthWithMargins( jHandleMultiFileDrop(vf<L<File>> onFileDrop, withCenteredTitle("Input videos to jump-cut & concatenate (you can drag&drop files here):", withRightAlignedButtons(sup, tableDependentButton(table, "Move up", r moveUp), tableDependentButton(table, "Move down", r moveDown), tableDependentButton(table, "Remove selected", r removeSelected) ))), vstackWithSpacing( centeredLine(withLabel("Total input duration:", dm_boldLabel('originalLength))), dm_ajc_parametersSection(), centeredLine(withLabel("Total output duration (est.):", dm_boldLabel('cutLength))), withLabel("Output video:", filePathInputWithBrowseButton(dm_textField('outputFile))), rightAlignedLine(fontSizePlus(3, jbutton("Make video", rThread makeVideo))), ffmpegVersionPanel() )); } void onFileDrop(L<File> files) enter { print("Have file drop"); Set<File> haveFiles = collectAsSet file(data()); addAll(map(listMinusSet(files, haveFiles), f -> nu VidFile(file := f))); rstScan.trigger(); } start { itemToMap = func(VidFile v) -> Map { litorderedmap( "Video" := fileName(v.file), "Folder" := dirPath(v.file), "Duration" := !fileExists(v.file) ? "File not found" : v.length < 0 ? "[calculating]" : formatMinuteAndSeconds(iceil(v.length)) ) }; rstScan.trigger(); dm_watchFields(allNonStaticNonTransientFields(AJCParameters), r recut); } void recut { for (VidFile v : clonedList()) v.ranges = null; rstScan.trigger(); } void scan { bool change; double lenIn = 0, lenOut = 0; for (VidFile v : clonedList()) pcall { if (v.ranges == null || v.length < 0 && fileExists(v.file)) { File audio = v.audioFile(); if (fileLength(audio) == 0) { print("Extracting audio from " + v.file); ffmpeg_toMonoAudio_16k(v.file, audio); // TODO: temp file for safety? v.profile = null; } if (v.profile == null) v.profile = decodeWAVToMonoSamples_floatVolumeProfile(audio, audioWindowSize); v.length = l(v.profile)*profileSamplingInterval; v.ranges = ajc_findSpeechPartsFromVolumeProfile(v.profile, shallowCloneToClass AJCParameters(module())); set change; } lenIn += v.length; lenOut += totalLengthOfDoubleRanges(v.ranges); } setField(originalLength := formatMinuteAndSeconds(iceil(lenIn)); setField(cutLength := formatMinuteAndSeconds(iceil(lenOut)); if (change) fireDataChanged(); } void makeVideo { temp dm_tempDisableAllButtons(); while (rstScan.running()) sleep(10); if (emptyAfterTrim(outputFile)) ret with infoBox("Need output file path"); File out = newFile(trim(outputFile)); L<VidFile> l = clonedList(); if (empty(l)) ret with infoBox("No input files"); if (fileExists(out) && !confirmOKCancel("Overwrite " + fileName(out) + "?")) ret; L<File> files = collect file(l); LL<DoubleRange> ranges = collect ranges(l); temp tempInfoBox_noHide("Splicing video..."); backtickToConsole(ffmpegCmd() + " -y " + ffmpeg_argsForSplice_multipleInputVideos(files, out, ranges)); if (fileExists(out)) infoBox("Done splicing video!" + fileInfo(out)); else infoBox("Something went wrong..."); } void moveUp { L<Int> indices = selectedIndices(); int i = first(indices), j = last(indices)+1; if (i <= 0) ret; VidFile v = data.get(i-1); remove(v); add(j-1, v); new L<Int> sel; for (int k = i; k < j; k++) sel.add(k-1); selectTableRows(table, asIntArray(sel)); } void moveDown { L<Int> indices = selectedIndices(); int i = first(indices), j = last(indices)+1; if (j >= l(data)) ret; VidFile v = data.get(j); remove(v); add(i, v); new L<Int> sel; for (int k = i; k < j; k++) sel.add(k+1); selectTableRows(table, asIntArray(sel)); } }
download show line numbers debug dex old transpilations
Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1024630 |
Snippet name: | AutoJumpCut Batch Mode (Concatenate All Videos) |
Eternal ID of this version: | #1024630/45 |
Text MD5: | c3fc75f21c48259711760d8b14b08d4a |
Transpilation MD5: | f3e6d307b30ad6c941ade157a29ebd57 |
Author: | stefan |
Category: | javax / ajc |
Type: | JavaX source code (Dynamic Module) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-01-09 22:25:25 |
Source code size: | 4932 bytes / 146 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 270 / 1089 |
Version history: | 44 change(s) |
Referenced in: | [show references] |