10

Professional video editor here who isn't skilled at FFmpeg, so bear with me. I have a large batch of videos, all different lengths, and I would like to trim them by 10 seconds at the beginning AND 10 seconds at the end.

I know there is a "-sseof" command that looks for a timecode based on the end of the video. However, I can only get it to give me the portion at the end, not the portion BEFORE the specified time. For instance, this just gives me the last 10 seconds:

ffmpeg -sseof -10 -i test.mp4 outputB.mp4

I want the exact opposite, everything UP to the last 10 seconds.

And I'd really like to combine it with a trim from the beginning. My ideal formula would look like this:

ffmpeg -i test.mp4 -ss 10 -to -sseof -10 output.mp4

But that doesn't work. Any suggestions? Thanks!

EDIT:

The solution suggested by Mulvya worked for me! Here's the formula I used to run the script on an entire folder, cutting 4.25 seconds from the beginning and 17.8 seconds from the end of each clip (those values need to be changed in several places each, but it works).

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

Thanks a lot!

5 Answers 5

10

There's a sane way to do this and an insane way. The sane way is to probe the duration in a separate command beforehand and shape your actual trim command using that info.

Probe command:

ffprobe -v 0 -show_entries format=duration -of compact=p=0:nk=1 in.mp4

This will produce a single line output:

194.834000

So, your command is now

ffmpeg -ss 10 -t 174.834 -i test.mp4 outputB.mp4

where t = total duration - 20 sec


The insane way is slower, but one command.

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
8
  • 2
    +1 for showing how to get length without grep and sed
    – MrFregg
    Commented Nov 29, 2016 at 15:52
  • This is great! Will both versions work with batches? It seems like the 2-step version would only work if you're doing one video at a time. Commented Nov 29, 2016 at 16:11
  • If both commands have to be run for each file, they can used in batch. Which OS are you on?
    – Gyan
    Commented Nov 29, 2016 at 16:22
  • I'm on a Mac, using Terminal. I tried to run the insane script but I'm getting a ton of errors like this:frame= 223 fps= 27 q=29.0 size= 457kB time=00:00:15.48 bitrate= 241.8kbits/[Parsed_overlay_1 @ 0x7fed78c088c0] [framesync @ 0x7fed78c089a8] Buffer queue overflow, dropping. Last message repeated 22 times frame= 246 fps= 29 q=29.0 size= 472kB time=00:00:16.25 bitrate= 237.9kbits/[Parsed_overlay_1 @ 0x7fed78c088c0] [framesync @ 0x7fed78c089a8] Buffer queue overflow, dropping. Last message repeated 18 times Commented Nov 29, 2016 at 16:26
  • Try edited cmd. Added buffer.
    – Gyan
    Commented Nov 29, 2016 at 16:35
1

I needed what @nvd wrote, so I improved it:

#!/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
0

The previous two answers served as the answer to the Windows CMD script here. It's the revision 1 and assumes the following:

  1. CONVERT.CMD (contents herein) live in the exact directory as the files.
  2. Variables at beginning of script are correct (namely file type and path)

This has been tested working as intended. Created on 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

PICTURE - Before running script.

PICTURE - After running script.

0

Just wanted to say thank you to Chris Hammer, this is exactly what I was looking for, however I do not know why you restricted apostrophe. I have since made a change to allow ' . HERE IT IS. Basically I just changed the ' to a ;.

  @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  5 and 7

@REM SET MISC. VARIABLES USED IN SCRIPT
@REM
set _vFileType=mkv
set _vTrimOffFront=5
set _vTrimOffRear=7
set _ffmpegPath=D:\Torrents\Video


@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"

Pause
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%"
0

A simple script for it ("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"

Usage example (strip 10 seconds at the beginning and 15 seconds at the end):

strip-video.sh "in.mp4" "out.mp4" 10 15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .