Published 2022-01-28.
Last modified 2023-11-28.
Time to read: 3 minutes.
av_studio collection.
This article discusses the technical implementation of
MediaTrim,
which I presented in the previous article.
Codecs and Re-Encoding
- Some of the
ffmpegoptions this script uses are not available in older versions offfmpeg. -
The most important thing to know about options that might be passed to
ffmpegis that arbitrary start and end times can be specified accurately when trimming if the video stream is re-encoded. To force a video re-encoding, simply do not specify the-vcodec copyoption. -
Non-essential streams in video files are discarded by the
MediaTrimtrimming process. See Selecting streams with the -map option.
Sony A7iii Media Files
I wanted to trim a video file created by my Sony A7iii camera, so only the portion from 0:51 through 2:45 was extracted.
FFprobe Provides Useful Information
FFprobe gathers information from multimedia streams and prints it in human- and machine-readable fashion.
For example, it can be used to check the format of the container used by a multimedia stream and the format and type of each media stream contained in it.
Let’s use ffprobe to examine the streams within the media file.
$ ffprobe myvideo.mp4 ffprobe version 5.1.2-3ubuntu1 Copyright (c) 2007-2022 the FFmpeg developers built with gcc 12 (Ubuntu 12.2.0-14ubuntu2) configuration: --prefix=/usr --extra-version=3ubuntu1 --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-libglslang --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librist --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --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 --disable-sndio --enable-libjxl --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-libplacebo --enable-librav1e --enable-shared libavutil 57. 28.100 / 57. 28.100 libavcodec 59. 37.100 / 59. 37.100 libavformat 59. 27.100 / 59. 27.100 libavdevice 59. 7.100 / 59. 7.100 libavfilter 8. 44.100 / 8. 44.100 libswscale 6. 7.100 / 6. 7.100 libswresample 4. 7.100 / 4. 7.100 libpostproc 56. 6.100 / 56. 6.100 [mov,mp4,m4a,3gp,3g2,mj2 @ 0x560a973df5c0] st: 0 edit list: 1 Missing key frame while searching for timestamp: 1001 [mov,mp4,m4a,3gp,3g2,mj2 @ 0x560a973df5c0] st: 0 edit list 1 Cannot find an index entry before timestamp: 1001. Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'myvideo.mp4': Metadata: major_brand : XAVC minor_version : 16785407 compatible_brands: XAVCmp42iso2 creation_time : 2023-01-05T00:52:24.000000Z Duration: 00:10:58.16, start: 0.000000, bitrate: 51445 kb/s Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709/bt709/iec61966-2-4, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 49370 kb/s, 59.94 fps, 59.94 tbr, 60k tbn (default) Metadata: creation_time : 2023-01-05T00:52:24.000000Z handler_name : Video Media Handler vendor_id : [0][0][0][0] encoder : AVC Coding Stream #0:1[0x2](und): Audio: pcm_s16be (twos / 0x736F7774), 48000 Hz, 2 channels, s16, 1536 kb/s (default) Metadata: creation_time : 2023-01-05T00:52:24.000000Z handler_name : Sound Media Handler vendor_id : [0][0][0][0] Stream #0:2[0x3](und): Data: none (rtmd / 0x646D7472), 491 kb/s (default) Metadata: creation_time : 2023-01-05T00:52:24.000000Z handler_name : Timed Metadata Media Handler timecode : 03:52:30:26 Unsupported codec with id 0 for input stream 2
FFprobe shows us that myvideo.mp4 has 3 streams, numbered from origin zero:
-
MPEG-4 video stream: encoded using the H.264
high profile, which is the most commonly used
H.264 profile,
with 1920x1080 resolution, recorded at 50 Mb/s, and 59.94 fps.
This stream was recoded to the same format using
FFmpeg’s default stream handling. The recoding process computes keyframes for the new start and points after trimming. -
CD-quality audio stream:
pcm_s16be(16-bitWAVformat), at 48 kHz, in stereo, with a bit rate of 1536 Kb/s. In contrast, 24 bits are commonly used in 2023 for streaming audio.WAVencoding is uncompressed, and so it is disallowed by strict MP4 compliance.
BecauseFFmpegfollows stringmp4compliance by default,FFmpegwill not copy audio encoded inWAVformat. However, the audio stream can be transcoded to a compressed format, so it can be included in the output file. You could relaxFFmpeg’s strictmp4compliance by providing the-strict experimentaloption toFFmpeg. Instead, I decided to compress the audio using AAC because this results in a smaller file that sounds just as good. -
Data stream: normally ignored by
ffmpegwhen creating output.ffprobeshows an error for this stream (Unsupported codec with id 0 for input stream 2), but we do not need this stream, so thetrimscript will also ignore it.
Transcoding Audio
Audio is best transcoded to a lossless compressed format that is supported by the MP4 container,
like aac
or Opus.
The hierarchy of audio encoder quality
has been reported as:
libopus > libvorbis >= libfdk_aac > libmp3lame >= eac3/ac3 > aac > libtwolame > vorbis > mp2 > wmav2/wmav1.
Ffmpeg’s AAC transcoder gives poor results for bit rates less than 128k.
Opus gives a better result; however, some hardware devices may not have support.
My 3-year-old TCL TV does not support Opus, for example.
Ffmpeg supports five AAC encoders, including the regular AAC encoder and the Fraunhofer FDK AAC codec. The latter requires that you compile FFmpeg because of licensing issues. This article will not get into that.
Regular AAC codec
The following is the incantation used by the trim script.
It yields a regular mp4 with a video stream and an AAC stereo stream.
$ ffmpeg -y -ss 51 -to 2:45 -i input.mp4 -acodec aac output.mp4
Both the video and audio streams are recoded. The video stream selected from the input file is the highest resolution video stream in that file. Non-essential streams for regular playback are ignored.
😁The resulting file is a balance of the highest-quality audio and video streams with the smallest overall file size that can usually be expected to play on most devices.
Fraunhofer FDK AAC codec
You could go one better and
build FFmpeg with the Fraunhofer FDK AAC codec,
then invoke it with:
$ ffmpeg -y -ss 51 -to 2:45 -i input.mp4 -c:a libfdk_aac output.mp4