Published 2022-01-23.
Time to read: 1 minutes.
When I use OBS Studio to record video from Cam Link 4K and audio from Pro Tools using RME TotalMix,
I get really large mkv
files.
I need to be able to trim the video file so the bits before and after the good stuff are discarded.
Lots of StackOverflow conversations revolve around trimming video files. Dozens of PC and Mac programs exist to do that task, mostly low quality and / or bothersome to use. Other solutions are overkill, for example Adobe Premiere Pro and DaVinci Resolve.
In this post I present a bash script that reduces file size by > 80%, while preserving quality and metadata, and cropping to specified time periods.
For any programmers who might read this:
- Some of the
ffmpeg
options this script uses are not available in older versions. -
The most important thing to know about options that might be passed to
ffmpeg
is that if you want to force a new video encoding, simply do not specify the-vcodec copy
option. Re-encoding means that arbitrary start and end times can be specified accurately when cropping.
This is the script:
#!/bin/bash function help { echo "$(basename $0) - Trim an audio or video file using ffmpeg Works with all formats supported by ffmpeg. Seeks to the nearest frame positions by re-encoding. Does not overwrite pre-existing output files. Reduces file size procduced by OBS Studio by >80%. Usage: $(basename $0) "dir/file.mkv" START [END] START and END have the format [HH:[MM:]]SS[.XXX] END defaults to end of audio/video file Examples: $(basename $0) 'dir/file.mkv' 15 # Crop from 15.0 seconds to end $(basename $0) 'dir/file.mkv' 3.25 9 # Crop from 3.25 seconds to 9 seconds " exit 1 } if [ -z "$2" ]; then help; fi if [ "$1" == -f ]; then shift OVERWRITE=-y else OVERWRITE=-n fi FNAME="$1" ORIGINAL_FN=${FNAME%.*} EXT=${FNAME##*.} COPY_FNAME="${ORIGINAL_FN}.crop.$EXT" START="$2" if [ "$3" ]; then TO="-to $3" else unset TO fi ffmpeg \ "$OVERWRITE" \ -i "$FNAME" \ -ss "$START" $TO \ -acodec copy \ "$COPY_FNAME"
Here is a sample session, which extracts the sequence beginning at
00:00:25.000
until 00:02:52.000
:
$ crop 'VideoFile.mkv' 25 2:52 ffmpeg version 4.4-6ubuntu5 Copyright (c) 2000-2021 the FFmpeg developers built with gcc 11 (Ubuntu 11.2.0-7ubuntu1) configuration: --prefix=/usr --extra-version=6ubuntu5 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared libavutil 56. 70.100 / 56. 70.100 libavcodec 58.134.100 / 58.134.100 libavformat 58. 76.100 / 58. 76.100 libavdevice 58. 13.100 / 58. 13.100 libavfilter 7.110.100 / 7.110.100 libswscale 5. 9.100 / 5. 9.100 libswresample 3. 9.100 / 3. 9.100 libpostproc 55. 9.100 / 55. 9.100 Input #0, matroska,webm, from 'VideoFile.mkv': Metadata: ENCODER : Lavf58.29.100 Duration: 00:02:57.93, start: 0.000000, bitrate: 8137 kb/s Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 1k tbn, 60 tbc (default) Metadata: DURATION : 00:02:57.933000000 Stream #0:1: Audio: aac (LC), 48000 Hz, stereo, fltp (default) Metadata: title : simple_aac_recording DURATION : 00:02:57.813000000 Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264)) Stream #0:1 -> #0:1 (copy) Press [q] to stop, [?] for help [libx264 @ 0x55fe8a8a6d40] using SAR=1/1 [libx264 @ 0x55fe8a8a6d40] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX [libx264 @ 0x55fe8a8a6d40] profile High, level 3.1, 4:2:0, 8-bit [libx264 @ 0x55fe8a8a6d40] 264 - core 160 r3011 cde9a93 - H.264/MPEG-4 AVC codec - Copyleft 2003-2020 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 Output #0, matroska, to 'VideoFile.crop.mkv': Metadata: encoder : Lavf58.76.100 Stream #0:0: Video: h264 (H264 / 0x34363248), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 1k tbn (default) Metadata: DURATION : 00:02:57.933000000 encoder : Lavc58.134.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A Stream #0:1: Audio: aac (LC) ([255][0][0][0] / 0x00FF), 48000 Hz, stereo, fltp (default) Metadata: title : simple_aac_recording DURATION : 00:02:57.813000000 frame= 4410 fps= 56 q=-1.0 Lsize= 29863kB time=00:02:26.98 bitrate=1664.3kbits/s speed=1.85x video:26295kB audio:3489kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.266039% [libx264 @ 0x55fe8a8a6d40] frame I:18 Avg QP:19.94 size: 91473 [libx264 @ 0x55fe8a8a6d40] frame P:1111 Avg QP:22.35 size: 14426 [libx264 @ 0x55fe8a8a6d40] frame B:3281 Avg QP:26.70 size: 2820 [libx264 @ 0x55fe8a8a6d40] consecutive B-frames: 0.8% 0.0% 0.1% 99.1% [libx264 @ 0x55fe8a8a6d40] mb I I16..4: 9.1% 68.8% 22.1% [libx264 @ 0x55fe8a8a6d40] mb P I16..4: 0.1% 1.2% 0.4% P16..4: 41.3% 11.1% 8.7% 0.0% 0.0% skip:37.2% [libx264 @ 0x55fe8a8a6d40] mb B I16..4: 0.0% 0.2% 0.0% B16..8: 25.8% 2.6% 0.6% direct: 0.7% skip:70.0% L0:42.9% L1:51.0% BI: 6.1% [libx264 @ 0x55fe8a8a6d40] 8x8 transform intra:71.2% inter:72.8% [libx264 @ 0x55fe8a8a6d40] coded y,uvDC,uvAC intra: 81.3% 83.4% 41.2% inter: 6.8% 12.5% 0.3% [libx264 @ 0x55fe8a8a6d40] i16 v,h,dc,p: 27% 14% 15% 44% [libx264 @ 0x55fe8a8a6d40] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 15% 15% 12% 7% 13% 9% 13% 7% 9% [libx264 @ 0x55fe8a8a6d40] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 15% 13% 11% 10% 17% 11% 10% 6% 7% [libx264 @ 0x55fe8a8a6d40] i8c dc,h,v,p: 46% 21% 21% 11% [libx264 @ 0x55fe8a8a6d40] Weighted P-Frames: Y:0.5% UV:0.1% [libx264 @ 0x55fe8a8a6d40] ref P L0: 56.5% 10.1% 21.4% 12.0% 0.0% [libx264 @ 0x55fe8a8a6d40] ref B L0: 87.7% 8.9% 3.4% [libx264 @ 0x55fe8a8a6d40] ref B L1: 94.4%
The cropped file is quite a bit smaller than the original. I have not noticed any decrease in quality.
$ ls -AlF total 1546136 -rw-r--r-- 1 mslinn mslinn 30579665 Jan 23 13:03 'VideoFile.crop.mkv' -rwxrwxrwx 1 mslinn mslinn 180988555 Jan 22 18:31 'VideoFile.mkv'