October 23, 2021, 08:35:41 AM



Avidemux Script for Cutting mp4

Started by brennanjohnson, October 03, 2021, 12:08:53 AM

Previous topic - Next topic


I have found this forum extremely useful in learning the capabilities of scripting in Avidemux, so I thought I might contribute the results. I have video files that contain advertisements, and I wanted to remove them. I have a program that calls ffmpeg to get the mp4 metadata, and parses it to give a list of non-advertisement video timestamps in a text file. Unfortunately, the timestamps are in milliseconds. Avidemux seems to choke when editing using non-exact timestamps for the addSegment command. My very old Windows Avidemux didn't seem to mind, but the newest Linux version 2.8.7 does (but is much more capable in every other way).

1. The solution for the exact timestamp issue was to open the entire video, step through key frames until the non-exact timestamp is exceeded, and the get the exact timestamp of that key frame. Works great, but perhaps I missed an easier way.

2. I have to paste the specific timestamp list into my Python script each time I run it. The list is in a simple text file. If Avidemux Python had a way of reading a text file, I could run batches. TinyPy does not appear to have any text file input capability, but perhaps I missed something there.

Perhaps someone will find this code useful. Please forgive the style. I just switched to Linux and I am an industrial programmer by trade (code must be as verbose and simple as possible).

#PY  <- Needed to identify #

# Avidemux script for removing parts of a video file.
# Brennan Johnson
# 2021-10-02
# Avidemux 2.7.8 on Kubuntu.

# Software flow:
# 1. User adds timelist_raw values from upstream program. These are the times when non-commercial video starts and ends. The source does not provide exact PTS values aligned to frames (i.e. 10_000_000 instead  of 10_153_253). The addSegment function requires exact PTS values, otherwise it will copy things incorrect. The resultant video ends up showing abnormal length in VLC and the video generally does not play properly.
# 2. Add full video as a addSegment.
# 3. seekFrame (or KeyFrame) through full video, comparing to value from list of timestamps. Loop through list. Output is list of EXACT time stamps.
# 4. ClearSegments.
# 5. Run normal addsegment loops using EXACT times stamps and output file.

# Note that Avidemux will throw a seek error during the save process. Cause is unknown, but the error does not harm the process.

adm = Avidemux()
ed = Editor()
gui = Gui()

fileextension = "mp4"
sourcedirectory = "/.../WorkDirectory/aSource/"
destdirectory = "/.../WorkDirectory/bDest/"
vTotalLen = 0
VStart = 0
VEnd = 0
vPTS = 0

# Get file name from source directory.
# !!! Code framework is based on earlier batch program, but is not written for batch processing. Source directory must only have one file in it. !!!
filelist=get_folder_content(sourcedirectory, fileextension)
if(filelist is None):
gui.displayError("Error","No files")

# Declaring corrected time list array. Values are modifed by program. Array length does not matter because _raw array is used for array length.
timelist_corr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]

# List of points (start1, end1, start2, end2, etc) from upstream program
timelist_raw = [0,1000000,8000000,482484000,605202000,1620715000,1697301000,2757354000,2894643000,3810622000,3948208000,4963471000]

# Load video file.

# Add entire video to allow for seeking.
vidlen = adm.markerB
adm.addSegment(0, 0, vidlen)

# Generate corrected (exact) timestamps nearest to the uncorrected (raw) timestamps.
for i in range(0, len(timelist_raw), 1):
    while vPTS < timelist_raw[i]:
        adm.seekKeyFrame(1) # Skip to next key frame.
        vPTS = ed.getCurrentPts() # Get correct PTS for frame
    timelist_corr[i] = vPTS

# Clear the palette.

# Run through each start and end pair in the corrected timelist, adding each segment.
for i in range(0, len(timelist_raw), 2): # timelist_raw is used for array length because timelist_corr is a pre-defined length for ease of programming.
    adm.addSegment(0, VStart, VEnd-VStart)
    vTotalLen = vTotalLen + (VEnd-VStart)

# Add markers at start (0) and end (total length of retained video).
adm.markerA = 0
adm.markerB = vTotalLen

# Copy and output.
adm.audioCodec(0, "copy");
adm.audioSetDrc(0, 0)
adm.audioSetShift(0, 0,0)
adm.setContainer("MP4V2", "optimize=0", "add_itunes_metadata=0")

gui.displayInfo("Commercials scrubbed.",filelist[0])


You might want to try a build off the current Avidemux code, there have been some changes which should have removed the requirement to match a frame PTS exactly when using scripting.