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

1  
!7
2  
3  
module VideoSplicer > DynPrintLog {
4  
  S inputFile, outputFile;
5  
  S timestamps;
6  
  S originalLength, cutLength;
7  
  S ffmpegOptions = "", videoCodec = "";
8  
  
9  
  int volumeThresholdPercent = 15;
10  
  S minSilence = "0.2", leadIn = "0.2", leadOut = "0.2";
11  
12  
  transient double profileSamplingInterval = 0.05; // 50 ms
13  
  transient int audioWindowSize = iround(profileSamplingInterval*16000);
14  
  
15  
  transient int timeFieldMinWidth = 40;
16  
  transient ImageSurface isPreview;
17  
  transient JAmplitudeGraph graph;
18  
  transient float[] profile;
19  
  
20  
  visual jHandleFileDrop(voidfunc(File f) { setField(inputFile := f2s(f)) },
21  
    northCenterAndSouthWithMargins(
22  
      vstackWithSpacing(
23  
        withLabel("Input video:", filePathInputWithBrowseButton(dm_textField inputFile(), onChoose := rThread loadVideo)),
24  
        withLabel("Output video:", filePathInputWithBrowseButton(dm_textField outputFile())),
25  
        centeredLine(
26  
          jbutton("Load video", rThread loadVideo),
27  
          jbutton("Find jump cuts", rThread autoJumpCuts),
28  
          jhspacer(10),
29  
          jbutton("Make video", rThread makeVideo)),
30  
        jCenteredSection("Jump Cut Parameters", centeredLineWithSpacing(20,
31  
          withLabelLeftAndRight("Volume threshold:", dm_spinner volumeThresholdPercent(0, 100), "%"),
32  
          withLabelLeftAndRight("Shortest silence to cut:", jMinWidth(timeFieldMinWidth, dm_centeredTextField minSilence()), "s"),
33  
          jline(
34  
            withLabel("Lead-in/out:", jMinWidth(timeFieldMinWidth, dm_centeredTextField leadIn())),
35  
            jlabel("/"),
36  
            withLabelToTheRight(jMinWidth(timeFieldMinWidth, dm_centeredTextField leadOut()), "s"))
37  
        ))),
38  
      jhsplit(0.2,
39  
        centerAndSouthWithMargin(
40  
          jLiveValueSection(dm_calculatedLiveValue(S, () -> "Timestamps (" + countLines(timestamps) + ")"), dm_textArea("timestamps")),
41  
          vstack(
42  
            rightAlignedLine(withLabel("Total in:", dm_label("originalLength"))),
43  
            rightAlignedLine(withLabel("Total out (est.):", dm_label("cutLength"))))
44  
        ),
45  
        northAndCenterWithMargin(
46  
          jsection("Audio", jMinHeight(50, graph =
47  
            setForeground(Color.red, swingNu(JAmplitudeGraph)))),
48  
          hgridWithSpacing(jsection("Preview", jscroll_center(isPreview = jImageSurface())),
49  
          super))),
50  
      jvstackWithSpacing(
51  
        ffmpegVersionPanel(),
52  
        hgridWithSpacing(dm_textFieldWithLabel ffmpegOptions(), dm_textFieldWithLabel videoCodec()))));
53  
    
54  
  void loadVideo enter {
55  
    temp dm_tempDisableAllButtons();
56  
    File f = newFile(inputFile);
57  
    if (!fileExists(f)) ret with infoBox("File not found: " + f2s(f));
58  
    S id = md5(f2s(f));
59  
    
60  
    File previewFile = prepareCacheProgramFile("preview-" + id + ".jpg");
61  
    File audioFile = prepareCacheProgramFile("preview-" + id + ".wav");
62  
    if (!fileExists(previewFile)) {
63  
      print("Getting preview image...");
64  
      ffmpeg_getSingleFrame(f, previewFile, 0.0);
65  
      print("Done");
66  
    } else print("Have preview image");
67  
    isPreview.setImageAndZoomToDisplay(loadImage2(previewFile));
68  
69  
    if (!fileExists(audioFile)) {
70  
      print("Extracting audio...");
71  
      ffmpeg_toMonoAudio_16k(f, audioFile);
72  
      print("Done - " + fileInfo(audioFile));
73  
    } else print("Have audio");
74  
    
75  
    print("Getting volume profile...");
76  
    profile = decodeWAVToMonoSamples_floatVolumeProfile(audioFile, audioWindowSize);
77  
    print("Have volume profile (" + nEntries(l(profile)) + ")");
78  
    setField(originalLength := formatMinuteAndSeconds(iceil(l(profile)*profileSamplingInterval)));
79  
    //printStruct(takeFirstOfFloatArray(100, profile));
80  
    
81  
    graph.setValues(profile);
82  
  }
83  
  
84  
  void makeVideo enter {
85  
    temp dm_tempDisableAllButtons();
86  
    if (empty(outputFile)) ret with infoBox("Need output file path");
87  
    File in = newFile(inputFile), out = newFile(outputFile);
88  
    if (empty(timestamps)) autoJumpCuts();
89  
    L<DoubleRange> ranges = parseTimestampRanges(timestamps);
90  
    if (empty(ranges)) ret with infoBox("No timestamps");
91  
    print(+ranges);
92  
    if (fileExists(out) && !confirmOKCancel("Overwrite " + fileName(out) + "?")) ret;
93  
    temp tempInfoBox_noHide("Splicing video...");
94  
    backtickToConsole(ffmpegCmd() + " -y " + ffmpegOptions + " " + ffmpeg_argsForSplice_usingFile(in, out, ranges,
95  
      beforeOut := empty(videoCodec) ? "" : "-vcodec " + videoCodec));
96  
    if (fileExists(out))
97  
      infoBox("Done splicing video!"  + fileInfo(out));
98  
    else
99  
      infoBox("Something went wrong...");
100  
  }
101  
  
102  
  void autoJumpCuts enter {
103  
    if (profile == null) loadVideo();
104  
    if (profile == null) ret;
105  
    L<DoubleRange> ranges = audio_findSpeechPartsFromVolumeProfile(profile, profileSamplingInterval,
106  
      volumeThreshold := volumeThresholdPercent/100.0,
107  
      minSilenceDuration := parseDouble(minSilence),
108  
      pre := parseDouble(leadIn),
109  
      post := parseDouble(leadOut));
110  
    setField(timestamps := formatTimestampRanges(ranges));
111  
    infoBox("Created " + nSlices(ranges) + ", ready to make video");
112  
  }
113  
  
114  
  start {
115  
    shouldKeepTempFiles = () -> true;
116  
    dm_watchField timestamps(r {
117  
      pcall-silent {
118  
        double len = totalLengthOfDoubleRanges(parseTimestampRanges(timestamps));
119  
        setField(cutLength := formatMinuteAndSeconds(iceil(len)));
120  
      }
121  
    });
122  
    
123  
    dm_watchField inputFile(r {
124  
      setField(outputFile := f2s(appendToBaseName(newFile(inputFile), "-cut")))
125  
    });
126  
  }
127  
}

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: 449 / 2895
Version history: 70 change(s)
Referenced in: [show references]