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

127
LINES

< > BotCompany Repo | #1024578 // AutoJumpCut (Single Video)

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

Uses 108K of libraries. Click here for Pure Java version (16066L/121K).

!7

module VideoSplicer > DynPrintLog {
  S inputFile, outputFile;
  S timestamps;
  S originalLength, cutLength;
  S ffmpegOptions = "", videoCodec = "";
  
  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);
  
  transient int timeFieldMinWidth = 40;
  transient ImageSurface isPreview;
  transient JAmplitudeGraph graph;
  transient float[] profile;
  
  visual jHandleFileDrop(voidfunc(File f) { setField(inputFile := f2s(f)) },
    northCenterAndSouthWithMargins(
      vstackWithSpacing(
        withLabel("Input video:", filePathInputWithBrowseButton(dm_textField inputFile(), onChoose := rThread loadVideo)),
        withLabel("Output video:", filePathInputWithBrowseButton(dm_textField outputFile())),
        centeredLine(
          jbutton("Load video", rThread loadVideo),
          jbutton("Find jump cuts", rThread autoJumpCuts),
          jhspacer(10),
          jbutton("Make video", rThread makeVideo)),
        jCenteredSection("Jump Cut Parameters", centeredLineWithSpacing(20,
          withLabelLeftAndRight("Volume threshold:", dm_spinner volumeThresholdPercent(0, 100), "%"),
          withLabelLeftAndRight("Shortest silence to cut:", jMinWidth(timeFieldMinWidth, dm_centeredTextField minSilence()), "s"),
          jline(
            withLabel("Lead-in/out:", jMinWidth(timeFieldMinWidth, dm_centeredTextField leadIn())),
            jlabel("/"),
            withLabelToTheRight(jMinWidth(timeFieldMinWidth, dm_centeredTextField leadOut()), "s"))
        ))),
      jhsplit(0.2,
        centerAndSouthWithMargin(
          jLiveValueSection(dm_calculatedLiveValue(S, () -> "Timestamps (" + countLines(timestamps) + ")"), dm_textArea("timestamps")),
          vstack(
            rightAlignedLine(withLabel("Total in:", dm_label("originalLength"))),
            rightAlignedLine(withLabel("Total out (est.):", dm_label("cutLength"))))
        ),
        northAndCenterWithMargin(
          jsection("Audio", jMinHeight(50, graph =
            setForeground(Color.red, swingNu(JAmplitudeGraph)))),
          hgridWithSpacing(jsection("Preview", jscroll_center(isPreview = jImageSurface())),
          super))),
      jvstackWithSpacing(
        ffmpegVersionPanel(),
        hgridWithSpacing(dm_textFieldWithLabel ffmpegOptions(), dm_textFieldWithLabel videoCodec()))));
    
  void loadVideo enter {
    temp dm_tempDisableAllButtons();
    File f = newFile(inputFile);
    if (!fileExists(f)) ret with infoBox("File not found: " + f2s(f));
    S id = md5(f2s(f));
    
    File previewFile = prepareCacheProgramFile("preview-" + id + ".jpg");
    File audioFile = prepareCacheProgramFile("preview-" + id + ".wav");
    if (!fileExists(previewFile)) {
      print("Getting preview image...");
      ffmpeg_getSingleFrame(f, previewFile, 0.0);
      print("Done");
    } else print("Have preview image");
    isPreview.setImageAndZoomToDisplay(loadImage2(previewFile));

    if (!fileExists(audioFile)) {
      print("Extracting audio...");
      ffmpeg_toMonoAudio_16k(f, audioFile);
      print("Done - " + fileInfo(audioFile));
    } else print("Have audio");
    
    print("Getting volume profile...");
    profile = decodeWAVToMonoSamples_floatVolumeProfile(audioFile, audioWindowSize);
    print("Have volume profile (" + nEntries(l(profile)) + ")");
    setField(originalLength := formatMinuteAndSeconds(iceil(l(profile)*profileSamplingInterval)));
    //printStruct(takeFirstOfFloatArray(100, profile));
    
    graph.setValues(profile);
  }
  
  void makeVideo enter {
    temp dm_tempDisableAllButtons();
    if (empty(outputFile)) ret with infoBox("Need output file path");
    File in = newFile(inputFile), out = newFile(outputFile);
    if (empty(timestamps)) autoJumpCuts();
    L<DoubleRange> ranges = parseTimestampRanges(timestamps);
    if (empty(ranges)) ret with infoBox("No timestamps");
    print(+ranges);
    if (fileExists(out) && !confirmOKCancel("Overwrite " + fileName(out) + "?")) ret;
    temp tempInfoBox_noHide("Splicing video...");
    backtickToConsole(ffmpegCmd() + " -y " + ffmpegOptions + " " + ffmpeg_argsForSplice_usingFile(in, out, ranges,
      beforeOut := empty(videoCodec) ? "" : "-vcodec " + videoCodec));
    if (fileExists(out))
      infoBox("Done splicing video!"  + fileInfo(out));
    else
      infoBox("Something went wrong...");
  }
  
  void autoJumpCuts enter {
    if (profile == null) loadVideo();
    if (profile == null) ret;
    L<DoubleRange> ranges = audio_findSpeechPartsFromVolumeProfile(profile, profileSamplingInterval,
      volumeThreshold := volumeThresholdPercent/100.0,
      minSilenceDuration := parseDouble(minSilence),
      pre := parseDouble(leadIn),
      post := parseDouble(leadOut));
    setField(timestamps := formatTimestampRanges(ranges));
    infoBox("Created " + nSlices(ranges) + ", ready to make video");
  }
  
  start {
    shouldKeepTempFiles = () -> true;
    dm_watchField timestamps(r {
      pcall-silent {
        double len = totalLengthOfDoubleRanges(parseTimestampRanges(timestamps));
        setField(cutLength := formatMinuteAndSeconds(iceil(len)));
      }
    });
    
    dm_watchField inputFile(r {
      setField(outputFile := f2s(appendToBaseName(newFile(inputFile), "-cut")))
    });
  }
}

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: #1024578
Snippet name: AutoJumpCut (Single Video)
Eternal ID of this version: #1024578/71
Text MD5: 386d898ea956c378a1fe24a4ddb9d49f
Transpilation MD5: ecea8d0bc520a9321fcc6a355e00d6ed
Author: stefan
Category: javax
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-02-25 02:47:40
Source code size: 5523 bytes / 127 lines
Pitched / IR pitched: No / No
Views / Downloads: 448 / 2894
Version history: 70 change(s)
Referenced in: [show references]