我是专业的视频编辑,但不熟练使用 FFmpeg,所以请多多包涵。我有一大批视频,长度各不相同,我想在开头和结尾处分别剪掉 10 秒。
我知道有一个“-sseof”命令可以根据视频的结尾查找时间码。但是,我只能让它给出结尾的部分,而不是指定时间之前的部分。例如,这只给出最后 10 秒:
ffmpeg -sseof -10 -i test.mp4 outputB.mp4
我想要的完全相反,一切都直到最后 10 秒。
我真的很想从一开始就将它与修剪结合起来。我的理想配方如下:
ffmpeg -i test.mp4 -ss 10 -to -sseof -10 output.mp4
但那不管用。有什么建议吗?谢谢!
编辑:
Mulvya 建议的解决方案对我有用!这是我在整个文件夹上运行脚本时使用的公式,从每个剪辑的开头剪切 4.25 秒,从结尾剪切 17.8 秒(这些值需要在几个地方分别更改,但它有效)。
for file in *.mp4; do ffmpeg -i $file -filter_complex "[0]split[s1][s2]; [s1]trim=4.25,setpts=PTS-STARTPTS,fifo[bv]; [s2]trim=4.25,setpts=(PTS-STARTPTS)+17.8/TB,fifo[v]; [bv][v]overlay=shortest=1,trim=17.8,setpts=PTS-STARTPTS[fv]; [0]volume=0[b];[0]adelay=17800|17800[a]; [b][a]amix=duration=first,volume=2,atrim=22.05,asetpts=PTS-STARTPTS[fa]" -map "[fv]" -map "[fa]" "${file%.mp4}-trimmed.mp4"; done
多谢!
答案1
有一种明智的方法和一种疯狂的方法可以做到这一点。明智的方法是事先在单独的命令中探测持续时间,然后使用该信息塑造实际的修剪命令。
探测命令:
ffprobe -v 0 -show_entries format=duration -of compact=p=0:nk=1 in.mp4
这将产生单行输出:
194.834000
所以你的命令现在是
ffmpeg -ss 10 -t 174.834 -i test.mp4 outputB.mp4
在哪里t = total duration - 20 sec
疯狂的方式比较慢,但是只需要一个命令。
ffmpeg -i in.mp4 -filter_complex
"[0]split[s1][s2];
[s1]trim=10,setpts=PTS-STARTPTS,fifo[bv];
[s2]trim=10,setpts=(PTS-STARTPTS)+10/TB,fifo[v];
[bv][v]overlay=shortest=1,trim=10,setpts=PTS-STARTPTS[fv];
[0]volume=0[b];[0]adelay=10000|10000[a];
[b][a]amix=duration=first,volume=2,atrim=20,asetpts=PTS-STARTPTS[fa]"
-map "[fv]" -map "[fa]" trimmed.mp4
答案2
我需要@nvd 写的内容,因此我改进了它:
#!/usr/bin/env bash
function help {
printf "$1
Saves original file with the .saved mid-extension
Usage example 1: strip 10 seconds at the beginning only, save original as in.saved.mp3:
$(basename $0) in.mp3 10
Usage example 2: strip 10 seconds at the beginning and 15 seconds at the end:
$(basename $0) in.mp4 10 15
"
exit 2
}
if [ "$1" = -h ]; then help; fi
if [ -z "$2" ]; then help 'Error: the length of time to strip from beginning must be specified.\n'; fi
MEDIA_FILE_ORIGINAL="$1"
MEDIA_FILE_CHOPPED="${1%.*}.chopped.${1##*.}"
MEDIA_FILE_SAVED="${1%.*}.saved.${1##*.}"
BEGIN_LENGTH="$2"
END_LENGTH=0
if [ "$3" ]; then END_LENGTH="$3"; fi
duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$MEDIA_FILE_ORIGINAL")
newDuration=$(python3 -c "print($duration - ($BEGIN_LENGTH + $END_LENGTH))")
ffmpeg -ss "$BEGIN_LENGTH" -t $newDuration -i "$MEDIA_FILE_ORIGINAL" -c copy "$MEDIA_FILE_CHOPPED"
if [ $? = 0 ]; then
mv "$MEDIA_FILE_ORIGINAL" "$MEDIA_FILE_SAVED"
mv "$MEDIA_FILE_CHOPPED" "$MEDIA_FILE_ORIGINAL"
fi
答案3
前两个答案是此处 Windows CMD 脚本的答案。它是修订版 1,并假设以下内容:
- CONVERT.CMD(本文中的内容)位于与文件相同的目录中。
- 脚本开头的变量是正确的(即文件类型和路径)
已测试,运行正常。在 Windows 10 上创建。
@echo on
@REM This basic CMD file is designed to live within the exact directory in which
@REM the files live. This is for simplicity. It can be edited to do more.
@REM
@REM SET MISC. VARIABLES USED IN SCRIPT
@REM
set _vFileType=mp4
set _vTrimOffFront=6
set _vTrimOffRear=6
set _ffmpegPath=C:\ffmpeg-20170308-3016e91-win64-static\bin
@REM CREATE EDITED DIRECTORY IF IT DOESN'T EXIST
@REM - Used to copy edited files using existing file names if user chooses to do so
@REM
if not exist .\EDITED mkdir .\EDITED
@REM DETECT PROBLEMS
@REM
dir /b | findstr "'"
if %ERRORLEVEL% EQU 0 (
cls
echo !!! ERROR - FOUND APOSTROPHE !!!
echo.
echo - Please remove characters from filename^(s^).
echo.
dir /b | findstr "'"
pause
exit
)
@REM FOR LOOP TO EDIT FILES AND DROP IN TO .\EDITED FOLDER
@REM
for /f "delims=" %%g in ('dir ^/b *.^%_vFileType%') do call :proc_ProcessFiles "%%g"
EXIT
@rem THIS IS THE END OF THE SCRIPT! ANYTHING BELOW THIS IS A PROCEDURE USED IN THE SCRIPT ABOVE
@rem THIS IS THE END OF THE SCRIPT! ANYTHING BELOW THIS IS A PROCEDURE USED IN THE SCRIPT ABOVE
@rem THIS IS THE END OF THE SCRIPT! ANYTHING BELOW THIS IS A PROCEDURE USED IN THE SCRIPT ABOVE
@rem *******************************************************************************************************
@rem *******************************************************************************************************
@rem *******************************************************************************************************
@rem THIS IS THE END OF THE SCRIPT! ANYTHING BELOW THIS IS A PROCEDURE USED IN THE SCRIPT ABOVE
@rem THIS IS THE END OF THE SCRIPT! ANYTHING BELOW THIS IS A PROCEDURE USED IN THE SCRIPT ABOVE
@rem THIS IS THE END OF THE SCRIPT! ANYTHING BELOW THIS IS A PROCEDURE USED IN THE SCRIPT ABOVE
:proc_ProcessFiles
set _vFilenameTemp=%1
@REM FOR LOOP TO DETERMINE DURATION OF RESPECTIVE FILE AND THEN PROCESS SAID FILE
@REM Note: Output of FFPROBE gives decimal number for length of video, however this can't be used in CMD files--so, only the integer is saved.
@REM - If 1525.12524 is returned, then only 1525 is assigned to the variable.
@REM
for /f "delims=. tokens=1" %%h in ('%_ffmpegPath%\ffprobe.exe -v 0 -show_entries format^=duration -of compact^=p^=0^:nk^=1 %_vFilenameTemp%') do set _vFileLengthTemp=%%h
@REM SET THE AMOUNT TO TRIM OFF OF THE END OF THE FILE. DETERMINED BY USING VARIABLES SPECIFIED AT BEGINNING OF FILE.
@REM
:: echo %_vFilenameTemp:~1,-1%
:: echo %_vFileLengthTemp%
set /a _vFileLengthTemp="%_vFileLengthTemp%-%_vTrimOffRear%-%_vTrimOffFront%"
:: echo %_vFileLengthTemp%
@REM DO CONVERSION OF FILE USING VARIABLES CREATED ABOVE
@REM
%_ffmpegPath%\ffmpeg.exe -ss %_vTrimOffFront% -t %_vFileLengthTemp% -i %_vFilenameTemp% -vcodec copy -acodec copy ".\EDITED\EDITED-%_vFilenameTemp:~1,-1%"
GOTO:EOF
答案4
它的简单脚本(“strip-video.sh”):
#!/usr/bin/env bash
duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$1")
newDuration=$(python3 -c "print($duration - ($3 + $4))")
ffmpeg -ss $3 -t $newDuration -i "$1" -c copy "$2"
使用示例(删除开头10秒和结尾15秒):
strip-video.sh "in.mp4" "out.mp4" 10 15