Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

146
LINES

< > BotCompany Repo | #1024630 // AutoJumpCut Batch Mode (Concatenate All Videos)

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

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]