Veel videogebruikers kennen FFmpeg niet, nochtans is het de basis van veel videosoftware. FFmpeg is gespecialiseerd in het converteren van audio-, videobestanden en streams zoals televisie- of webcambeelden. Om video te converteren is FFmpeg ook in staat informatie weer te geven, zoekopdrachten uit te voeren, filters toe te passen, tekst of ondertitels toe te voegen, enz. M.a.w. met FFmpeg kan je video's op verschillende manieren bewerken.
FFmpeg werkt op alle computers, maar sommige bewerkingen kunnen op minder krachtige computers zeer lang duren. De bewerkingsduur is niet alleen afhankelijk van de computerhardware, maar ook van de lengte van de video. M.a.w. zelf op zeer krachtige computers duurt het bewerken van lange video's soms verschillende uren.
Veel distributies verwijderen licentie gevoelige onderdelen uit FFmpeg, zodat veel essentiële functies en mogelijkheden ontbreken. Op de webpagina van FFmpeg kan je echter een statische versie downloaden. Statische versie van software bevatten alle noodzakelijke onderdelen en zijn daardoor niet afhankelijk van systeemonderdelen. M.a.w. ze werken op alle distributies zonder beperkingen. De statische FFmpeg versie voor Linux kan je vinden op de FFmpeg Static Builds webpagina van John Van Sickle. Deze webpagina bevat een per processortype geoptimaliseerde versie. Voor 64 bits Intel/AMD processors download je het bestand ffmpeg-release-amd64-static.tar.xz.
Dit bestand pak je in de terminal uit met de volgende opdrachten:
dany@pindabackup:~>cd Downloads/
dany@pindabackup:~/Downloads>tar -xf ffmpeg-release-amd64-static.tar.xz
Om informatie over een videobestand weer te geven, gebruik je de -i optie. De optie -hide_banner zorgt dat we alleen de informatie zien en niet de overzichtsmeldingen van FFmpeg. Maar eerst betreden we de map met de FFmpeg software met de cd opdracht:
dany@pindabackup:~/Downloads>cd ffmpeg-4.2.1-amd64-static/
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static>./ffmpeg -i ../Haardvuur.webm -hide_banner
Input #0, matroska,webm, from '../Haardvuur.webm': Metadata: encoder : google/video-file Duration: 03:00:13.40, start: 0.000000, bitrate: 8760 kb/s Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 2560x1440, SAR 1:1 DAR 16:9, 24.98 fps, 24.98 tbr, 1k tbn, 1k tbc (default) At least one output file must be specified
Het te onderzoeken videobestand Haardvuur.webm staat in de Download map, vandaar de verwijzing ../ (bovenliggende map).
Zoals uit de informatie blijkt, duurt deze video meer dan 3 uur. Maar dikwijls bestaat zo'n video uit korte videofragmenten die steeds herhaald worden (loops). Met de volgende opdracht vergelijkt FFmpeg het eerste videobeeld met alle volgende videobeelden. Indien het verschil een zwart scherm oplevert, heeft FFmpeg eenzelfde beeld gevonden. Hoogstwaarschijnlijk dus de plaats waar de volgende videolus (-loop) start.
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static> ./ffmpeg -i ../Haardvuur.webm -hide_banner -filter_complex "[0]trim=start_frame=0:end_frame=1[c];[c][0]blend=all_mode=difference,blackframe" -f null -
Input #0, matroska,webm, from '../Haardvuur.webm':
Metadata:
encoder : google/video-file
Duration: 03:00:13.40, start: 0.000000, bitrate: 8760 kb/s
Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 2560x1440, SAR 1:1 DAR 16:9, 24.98 fps, 24.98 tbr, 1k tbn, 1k tbc (default)
Stream mapping:
Stream #0:0 (vp9) -> trim
Stream #0:0 (vp9) -> blend:bottom
blackframe -> Stream #0:0 (wrapped_avframe)
Press [q] to stop, [?] for help
[Parsed_blackframe_2 @ 0x6260600] frame:0 pblack:100 pts:0 t:0.000000 type:I last_keyframe:0
Output #0, null, to 'pipe:':
Metadata:
encoder : Lavf58.29.100
Stream #0:0: Video: wrapped_avframe, yuv420p, 2560x1440 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 24.98 fps, 24.98 tbn, 24.98 tbc (default)
Metadata:
encoder : Lavc58.54.100 wrapped_avframe
[Parsed_blackframe_2 @ 0x6260600] frame:750 pblack:100 pts:30030 t:30.030000 type:I last_keyframe:750
[Parsed_blackframe_2 @ 0x6260600] frame:1500 pblack:100 pts:60060 t:60.060000 type:I last_keyframe:1500
[Parsed_blackframe_2 @ 0x6260600] frame:2251 pblack:100 pts:90130 t:90.130000 type:I last_keyframe:2251
[Parsed_blackframe_2 @ 0x6260600] frame:3001 pblack:99 pts:120160 t:120.160000 type:I last_keyframe:3001
[Parsed_blackframe_2 @ 0x6260600] frame:3751 pblack:100 pts:150190 t:150.190000 type:I last_keyframe:3751
[Parsed_blackframe_2 @ 0x6260600] frame:4501 pblack:100 pts:180220 t:180.220000 type:I last_keyframe:4501
frame= 4590 fps=145 q=-0.0 Lsize=N/A time=00:03:03.78 bitrate=N/A speed= 5.8x
video:2403kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Exiting normally, received signal 2.
Al vlug blijkt dat om de 750 beelden (frames) een videofragment wordt herhaald. Ik heb de opdracht dan ook met Ctrl+c afgebroken.
Om een videofragment uit te knippen, moet je een begintijd en eindtijd opgeven. Uit de informatie blijkt dat de video 25 beelden per seconde weergeeft (24.98 fps). 750 beelden is dus 750/25 of 30 seconden beeldmateriaal. Om het herhalende videofragment uit het videobestand te knippen, gebruik je de opdracht:
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static> ./ffmpeg -ss 0 -i ../Haardvuur.webm -hide_banner -t 30 -c copy ../Haardvuur_loop.webm
Input #0, matroska,webm, from '../Haardvuur.webm':
Metadata:
encoder : google/video-file
Duration: 03:00:13.40, start: 0.000000, bitrate: 8760 kb/s
Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 2560x1440, SAR 1:1 DAR 16:9, 24.98 fps, 24.98 tbr, 1k tbn, 1k tbc (default)
Output #0, webm, to '../Haardvuur_loop.webm':
Metadata:
encoder : Lavf58.29.100
Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 2560x1440 [SAR 1:1 DAR 16:9], q=2-31, 24.98 fps, 24.98 tbr, 1k tbn, 1k tbc (default)
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
frame= 750 fps=0.0 q=-1.0 Lsize= 32411kB time=00:00:29.99 bitrate=8853.0kbits/s speed=1.12e+03x
video:32404kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.020291%
Ik heb een nog werkende oude monitor met een resolutie van 1600x1200. Deze schermverhouding zie je vandaag de dag niet meer. Samen met een Raspberry Pi wil ik er een kunstmatig haardvuur van maken. M.a.w. mijn haardvuur video met een resolutie van 2560x1440 moet ik omzetten naar 1600x1200 om de video beeldschermvullend zonder zwarte randen weer te geven.
Daarvoor maak ik eerst een werkmap aan:
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static> mkdir ../Haardvuur
Een video bestaat uit verschillende beelden die snel na elkaar worden weergegeven. We halen deze beelden uit de video en slaan deze op in de daarstraks aangemaakte werkmap:
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static> ./ffmpeg -i ../Haardvuur_loop.webm -hide_banner -qscale:v 2 ../Haardvuur/haardvuur_%09d.jpg
Input #0, matroska,webm, from '../Haardvuur_loop.webm':
Metadata:
ENCODER : Lavf58.29.100
Duration: 00:00:30.03, start: 0.000000, bitrate: 8841 kb/s
Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 2560x1440, SAR 1:1 DAR 16:9, 24.98 fps, 24.98 tbr, 1k tbn, 1k tbc (default)
Metadata:
DURATION : 00:00:30.030000000
Stream mapping:
Stream #0:0 -> #0:0 (vp9 (native) -> mjpeg (native))
Press [q] to stop, [?] for help
[swscaler @ 0x6066a40] deprecated pixel format used, make sure you did set range correctly
Output #0, image2, to '../Haardvuur/haardvuur_%09d.jpg':
Metadata:
encoder : Lavf58.29.100
Stream #0:0(eng): Video: mjpeg, yuvj420p(pc), 2560x1440 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 24.98 fps, 24.98 tbn, 24.98 tbc (default)
Metadata:
DURATION : 00:00:30.030000000
encoder : Lavc58.54.100 mjpeg
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
frame= 750 fps= 82 q=2.0 Lsize=N/A time=00:00:30.03 bitrate=N/A speed=3.27x
video:198729kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
De -qscale:v optie bepaald de kwaliteit van de opgeslagen jpeg beelden (2 is hoge kwaliteit). De %09d in de bestandsnaam wordt bij elk beeld vervangen door het beeldnummer met nullen voor tot deze samen 9 cijfers bevatten.
De beelden kunnen nu door een fotobewerkingsprogramma geschaald en bijgeknipt worden tot de gewenste resolutie. Ik gebruik hiervoor ImageMagick (de basis voor veel fotobewerkingssoftware). ImageMagick is standaard in openSUSE Leap 15.1 geïnstalleerd. De schaal- en knip ImageMagick opdracht die ik nodig heb is:
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static>cd ../Haardvuur/
dany@pindabackup:~/Downloads/Haardvuur>mogrify -scale "1600x1200^" -gravity center -crop "1600x1200+0+0" +repage "haardvuur*.jpg"
De eerste opdracht opent de map met de aan te passen beelden. De mogrify opdracht zorgt dat de beelden geschaald en bijgeknipt worden.
Nu de beelden de juiste resolutie hebben, kunnen we er terug een video van maken. Dit gaat met de volgende opdrachten:
dany@pindabackup:~/Downloads/Haardvuur>cd ../ffmpeg-4.2.1-amd64-static/
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static>./ffmpeg -i ../Haardvuur/haardvuur_%09d.jpg -hide_banner -i ../Haardvuur_loop.m4a -acodec copy ../Haardvuur/haardvuur.mp4
Input #0, image2, from '../Haardvuur/haardvuur_%09d.jpg': Duration: 00:00:30.00, start: 0.000000, bitrate: N/A Stream #0:0: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 1600x1200 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 25 tbn, 25 tbc Input #1, mov,mp4,m4a,3gp,3g2,mj2, from '../Haardvuur_loop.m4a': Metadata: major_brand : M4A minor_version : 512 compatible_brands: isomiso2 encoder : Lavf58.29.100 Duration: 00:00:30.00, start: 0.000000, bitrate: 129 kb/s Stream #1:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default) Metadata: handler_name : ISO Media file produced by Google Inc. Stream mapping: Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (libx264)) Stream #1:0 -> #0:1 (copy) Press [q] to stop, [?] for help [image2 @ 0x77b0940] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8) [libx264 @ 0x77b58c0] using SAR=1/1 [libx264 @ 0x77b58c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 [libx264 @ 0x77b58c0] profile Progressive High, level 4.0, 4:2:0, 8-bit [libx264 @ 0x77b58c0] 264 - core 157 r2969 d4099dd - H.264/MPEG-4 AVC codec - Copyleft 2003-2019 - 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, mp4, to '../Haardvuur/haardvuur.mp4': Metadata: encoder : Lavf58.29.100 Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuvj420p(pc), 1600x1200 [SAR 1:1 DAR 4:3], q=-1--1, 25 fps, 12800 tbn, 25 tbc Metadata: encoder : Lavc58.54.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1 Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default) Metadata: handler_name : ISO Media file produced by Google Inc. frame= 750 fps= 31 q=-1.0 Lsize= 25420kB time=00:00:29.97 bitrate=6946.8kbits/s speed=1.25x video:24925kB audio:469kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.101611% [libx264 @ 0x77b58c0] frame I:4 Avg QP:21.73 size: 91765 [libx264 @ 0x77b58c0] frame P:199 Avg QP:23.86 size: 43404 [libx264 @ 0x77b58c0] frame B:547 Avg QP:25.50 size: 30198 [libx264 @ 0x77b58c0] consecutive B-frames: 2.7% 0.0% 0.8% 96.5% [libx264 @ 0x77b58c0] mb I I16..4: 15.1% 76.9% 8.0% [libx264 @ 0x77b58c0] mb P I16..4: 9.0% 30.9% 1.6% P16..4: 30.6% 9.6% 4.0% 0.0% 0.0% skip:14.3% [libx264 @ 0x77b58c0] mb B I16..4: 4.8% 16.8% 0.9% B16..8: 25.5% 8.2% 1.8% direct: 4.6% skip:37.4% L0:50.6% L1:43.9% BI: 5.5% [libx264 @ 0x77b58c0] 8x8 transform intra:74.6% inter:85.8% [libx264 @ 0x77b58c0] coded y,uvDC,uvAC intra: 50.3% 85.6% 47.5% inter: 19.6% 33.8% 3.1% [libx264 @ 0x77b58c0] i16 v,h,dc,p: 29% 24% 5% 41% [libx264 @ 0x77b58c0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 34% 12% 15% 3% 7% 12% 5% 8% 4% [libx264 @ 0x77b58c0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 35% 12% 10% 4% 10% 13% 6% 6% 3% [libx264 @ 0x77b58c0] i8c dc,h,v,p: 34% 16% 33% 17% [libx264 @ 0x77b58c0] Weighted P-Frames: Y:1.0% UV:1.0% [libx264 @ 0x77b58c0] ref P L0: 40.8% 8.4% 28.4% 22.2% 0.2% [libx264 @ 0x77b58c0] ref B L0: 68.6% 21.6% 9.7% [libx264 @ 0x77b58c0] ref B L1: 87.5% 12.5% [libx264 @ 0x77b58c0] kb/s:6806.07
Tegelijkertijd heb ik het knetteren van het hout (../Haardvuur_loop.m4a) toegevoegd. Let er echter op dat de video en het geluid even lang duren.
FFmpeg het bijknippen, schalen en geluid toevoegen in één enkele opdracht uitvoeren. Dus zonder eerst alle afzonderlijke beelden af te zonderen, deze met een beeldbewerker aan te passen en de beelden terug in een video te plaatsen.
dany@pindabackup:~/Downloads/ffmpeg-4.2.1-amd64-static> ./ffmpeg -y -hide_banner -i ../Haardvuur_loop.webm -i ../Haardvuur_loop.m4a -acodec copy -filter:v "crop=iw-426:ih-0,scale=1600:1200,setdar=dar=4/3" ../haardvuur.mp4
Input #0, matroska,webm, from '../Haardvuur_loop.webm':
Metadata:
ENCODER : Lavf58.29.100
Duration: 00:00:30.03, start: 0.000000, bitrate: 8841 kb/s
Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 2560x1440, SAR 1:1 DAR 16:9, 24.98 fps, 24.98 tbr, 1k tbn, 1k tbc (default)
Metadata:
DURATION : 00:00:30.030000000
Input #1, mov,mp4,m4a,3gp,3g2,mj2, from '../Haardvuur_loop.m4a':
Metadata:
major_brand : M4A
minor_version : 512
compatible_brands: isomiso2
encoder : Lavf58.29.100
Duration: 00:00:30.00, start: 0.000000, bitrate: 129 kb/s
Stream #1:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : ISO Media file produced by Google Inc.
Stream mapping:
Stream #0:0 -> #0:0 (vp9 (native) -> h264 (libx264))
Stream #1:0 -> #0:1 (copy)
Press [q] to stop, [?] for help
[swscaler @ 0x67808c0] Warning: data is not aligned! This can lead to a speed loss
[libx264 @ 0x66d3c40] using SAR=1/1
[libx264 @ 0x66d3c40] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x66d3c40] profile Progressive High, level 4.0, 4:2:0, 8-bit
[libx264 @ 0x66d3c40] 264 - core 157 r2969 d4099dd - H.264/MPEG-4 AVC codec - Copyleft 2003-2019 - 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=24 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, mp4, to '../haardvuur.mp4':
Metadata:
encoder : Lavf58.29.100
Stream #0:0(eng): Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 1600x1200 [SAR 1:1 DAR 4:3], q=-1--1, 24.98 fps, 25k tbn, 24.98 tbc (default)
Metadata:
DURATION : 00:00:30.030000000
encoder : Lavc58.54.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : ISO Media file produced by Google Inc.
frame= 750 fps= 33 q=-1.0 Lsize= 23450kB time=00:00:29.97 bitrate=6408.3kbits/s speed= 1.3x
video:22955kB audio:469kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.110534%
[libx264 @ 0x66d3c40] frame I:4 Avg QP:21.08 size: 94527
[libx264 @ 0x66d3c40] frame P:188 Avg QP:23.16 size: 41404
[libx264 @ 0x66d3c40] frame B:558 Avg QP:25.33 size: 27496
[libx264 @ 0x66d3c40] consecutive B-frames: 0.7% 0.3% 0.4% 98.7%
[libx264 @ 0x66d3c40] mb I I16..4: 14.5% 74.8% 10.6%
[libx264 @ 0x66d3c40] mb P I16..4: 8.2% 28.6% 2.0% P16..4: 34.1% 9.0% 3.8% 0.0% 0.0% skip:14.2%
[libx264 @ 0x66d3c40] mb B I16..4: 4.3% 15.3% 1.1% B16..8: 24.3% 6.8% 1.5% direct: 6.1% skip:40.7% L0:50.7% L1:44.0% BI: 5.3%
[libx264 @ 0x66d3c40] 8x8 transform intra:73.9% inter:84.3%
[libx264 @ 0x66d3c40] coded y,uvDC,uvAC intra: 51.6% 82.8% 36.9% inter: 18.7% 35.5% 1.8%
[libx264 @ 0x66d3c40] i16 v,h,dc,p: 33% 20% 5% 41%
[libx264 @ 0x66d3c40] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 37% 10% 14% 3% 6% 13% 4% 8% 4%
[libx264 @ 0x66d3c40] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 39% 10% 10% 4% 9% 13% 5% 7% 3%
[libx264 @ 0x66d3c40] i8c dc,h,v,p: 34% 14% 35% 16%
[libx264 @ 0x66d3c40] Weighted P-Frames: Y:1.6% UV:1.1%
[libx264 @ 0x66d3c40] ref P L0: 41.5% 9.4% 27.8% 20.9% 0.4%
[libx264 @ 0x66d3c40] ref B L0: 68.8% 21.3% 9.8%
[libx264 @ 0x66d3c40] ref B L1: 88.1% 11.9%
[libx264 @ 0x66d3c40] kb/s:6261.74
Tenslotte kan je de video gebruiken en deze schermvullend afspelen in een eindeloze lus. Als het afspelen van de video dan automatisch start bij het opstarten van de Raspberry Pi is het helemaal feest.
FFmpeg wordt door zoveel mensen gebruikt dat je voor elke videotaak wel informatie vindt om deze met FFmpeg tot een goed einde te brengen. Naast de handleidingen in de man-, info- en webpagina van FFmpeg zijn er heel wat toepassingen te vinden op internet. Succes ermee.