Auteur Sujet: FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)  (Lu 433 fois)

0 Membres et 1 Invité sur ce sujet

vivien

  • Administrateur
  • *
  • Messages: 39 132
    • Twitter LaFibre.info
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« le: 06 septembre 2021 à 10:44:47 »
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)

Pour encoder une vidéo, vous pouvez soit demander :
- une qualité fixe (recommandé) :  le débit va varier pour que la qualité de la vidéo soit stable
- un débit moyen fixe (par exemple pour que la vidéo rentre dans un DVD qui a une taille fixe), mais le débit peut varier dans ce fichier, sans dépasser le débit d'un lecteur DVD
- un débit strictement fixe. Le débit est fixe sur un intervalle de temps (le buffer) donné.

Il est fortement recommandé de laisser le débit varier, car certains scène fixe de vidéos ne nécessitent presque pas de débit pour être encodé en bonne qualité et d'autres, comme des images ou le premier plan et l’arrière plan change rapidement nécessitent beaucoup de débit. Le débit fixe va donc gaucher des octets sur les scènes peu animées et la qualité sera dégradée sur les scènes animées.

Voici un exemple de ligne de commande FFmpeg pour encoder la vidéo avec une qualité vidéo fixe ( 29 ) et une qualité audio fixe ( 0.8 ). La résolution est également réduite à du 720p, le volume audio augmenté de 5db et avec ac 1 on passe la bande audio en mono.

ffmpeg -i "test.mp4" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -crf 29 -filter:a "volume=5dB" -c:a aac -q:a 0.8 -ac 1 "out.mp4"



Si la qualité constante est à privilégier, certains usage nécessite de forcer l'encodeur à toujours utiliser un certain débit, qui ne peut pas varier à la baisse et encore moins à la hausse. C'est ce que nous allons voir ci-dessous. Le débit sera toujours (à peu près) le même, même s'il n'est pas nécessaire.

Vous pouvez l'activer pour x264 en définissant l'option nal-hrd : -x264-params "nal-hrd=cbr:force-cfr=1"

J'ai testé l'option -cbr true, mais cela ne donne pas un encodage cbr (alors qu'en replaçant uniquement -cbr true par -x264-params "nal-hrd=cbr:force-cfr=1" on a bien du CBR)

Le débit est fixe mais il peut heureusement varier sur un intervalle donné, le buffer. Il faut donc définir avec soins le buffer.

Plus le buffer sera grand, plus la qualité sera élevée, mais plus on a un flux qui devient variable. Le buffer est donc généralement fixé par la taille du buffer de l'équipement qui demande un débit fixe.Par exemple cela peut être 2 Mbit. Ce buffer doit être plus important, plus le débit d'encodage est élevé (FFmpeg ne le permet pas, mais vous pouvez raisonner dans votre tête d'une taille du buffer en secondes ou ms, car un buffer peut être inférieur a une durée d'une seconde).

Bien sur, le buffer ne peut pas être plus petit qu'une image.
Dans mon cas, en 720p encodé à 2 Mbit/s, une frame fait 80 Kbit, qui est donc la taille minimum du buffer.
En 1080p, encodé à 4,2 Mbit/s, une frame fait 168 Kbit, qui est la taille minimum du buffer.

De mon coté, l'encodage à débit fixe avait pour but d'avoir des fichier de taille identique, pour une même durée, quel que soit le contenu encodé.

Voici ce que j'ai retenu comme paramètres FFmpeg, résolution par résolution :




240p : Résolution 426x240, débit vidéo fixe de 400 kbit/s (buffer de 300 kbit), débit audio fixe de 56 kbit/s.

ffmpeg -i "original.mp4" -filter:v "=426:240" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 400k -minrate 400k -maxrate 400k -bufsize 300k -c:a aac -b:a 56k "modif-240p.mp4"



360p : Résolution 640x360, débit vidéo fixe de 500 kbit/s (buffer de 400 kbit), débit audio fixe de 64 kbit/s.

ffmpeg -i "original.mp4" -filter:v "scale=640:360" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 500k -minrate 500k -maxrate 500k -bufsize 400k -c:a aac -b:a 64k "modif-360p.mp4"



480p : Résolution 854x480 débit vidéo fixe de 900 kbit/s (buffer de 500 kbit), débit audio fixe de 96 kbit/s.

ffmpeg -i "original.mp4" -filter:v "scale=854:480" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 900k -minrate 900k -maxrate 900k -bufsize 500k -c:a aac -b:a 96k "modif-480p.mp4"



HD 720p : Résolution 1280x720, débit vidéo fixe de 2 Mbit/s (buffer de 600 kbit), l'audio est une recopie de l'encodage source bit à bit, car il convient (il est à 128 Kb/s).

ffmpeg -i "original.mp4" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 2000k -minrate 2000k -maxrate 2000k -bufsize 600k -c:a copy "modif-720p.mp4"



HD 1080p : Résolution 1920x1080, débit vidéo fixe de 4,2 Mbit/s (buffer de 800 kbit), l'audio est une recopie de l'encodage source bit à bit, car il convient (il est à 128 Kb/s).

ffmpeg -i "original.mp4" -filter:v "scale=1920:1080" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 4200k -minrate 4200k -maxrate 4200k -bufsize 800k -c:a copy "modif-1080p.mp4"



4K 2160p : On ne touche pas à la résolution et l'audio du flux. Débit vidéo fixe de 14 Mbit/s (buffer de 2 Mbit).

ffmpeg -i "original.mp4" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 14000k -minrate 14000k -maxrate 14000k -bufsize 2000k -c:a copy "modif-2160p.mp4"

vivien

  • Administrateur
  • *
  • Messages: 39 132
    • Twitter LaFibre.info
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #1 le: 06 septembre 2021 à 10:45:14 »
Pour les résolutions 720p et 1080p, j'ai testé plusieurs valeur du buffer sur 5 vidéos bien différentes. Les 5 vidéos sont d'une durée de 30 secondes et je cherche à avoir la taille de fichier la plus proche.

Dans chaque colonne, j'ai fais varier la taille du buffer, le seul élément qui a changé et dans le tableau, les cases colorées sont la taille des fichiers en octets (mon fichier fait 8,3 Mo en 720p et 16,8 Mo en 1080p).
La taille de buffer "one frame" correspond à 80 Kbit en 720p et 168 Kbit en 1080p, c'est la taille minimum du buffer.

Je cherche à avoir la taille de buffer la plus élevée (pour avoir la meilleure qualité) avec une taille de fichier le plus stable quel que soit le débit encodé.
Pour noter la différence de taille entre le fichier le plus gros et le fichier le plus petit, j'ai rajouté une ligne "Max-min" qui est la soustraction du poids du fichier le plus lourd et du plus léger.
Dans les valeur faible de buffer, on a habituellement autour de 20 Ko de différence entre les deux.
Dans les buffer important, comme 8400 Kbit, on a par contre une taille qui varie significativement, de 16,7 Mo à 17,2 Mo (475 Ko de différence).


(Cliquer sur le tableau pour zoomer)

vivien

  • Administrateur
  • *
  • Messages: 39 132
    • Twitter LaFibre.info
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #2 le: 06 septembre 2021 à 23:14:11 »
Même si le contenu de votre vidéo est homogène (pas de partie simple à encoder et de partie complexe à encoder), un débit variable est plus intéressant.

Dans le cas d'une vidéo à encoder simple, les premières images seront plus floues en CBR qu'en VBR.

Même pour une vidéo complexe à encoder et avec un débit CBR important, on va avoir des dégradation par rapport à un débit VBR.

Voici quelques seconde de vidéos, filmées depuis un RER à environ 60 Km/s. Il y a beaucoup de mouvent, c'est donc complexe à encoder.

Les deux fichiers ont la même taille :
- VBR : Vidéo H.264 High à 3625 Kbit/s - Audio AAC 108 Kbit/s. Poids total : 5 850 308 octets
- CBR : Vidéo H.264 High à 3625 Kbit/s - Audio AAC 108 Kbit/s. Poids total : 5 850 518 octets

Ligne d'encodage VBR : ffmpeg -i "202109_rerb_bourg-la-reine.mp4" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -crf 29 -filter:a "volume=5dB" -c:a aac -q:a 0.8 "202109_rerb_bourg-la-reine_vbr.mp4"

Ligne d'encodage CBR : ffmpeg -i "202109_rerb_bourg-la-reine.mp4" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 3630k -minrate 3630k -maxrate 3630k -bufsize 600k -filter:a "volume=5dB" -c:a aac -b:a 107k "202109_rerb_bourg-la-reine_cbr.mp4"

Vidéo VBR :


Vidéo CBR :


Original : Vidéo H.264 High à 12 Mbit/s - Audio AAC 256 Kbit/s. Poids total : 19 193 097 octets

vivien

  • Administrateur
  • *
  • Messages: 39 132
    • Twitter LaFibre.info
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #3 le: 11 septembre 2021 à 15:28:28 »
Octets ou bits de bourrage, pour avoir un débit constant

Le format de sortie .ts (container MPEG-2 TS, utilisable également avec H.264), prend en charge le bourrage d'octets (ce n'est pas le cas de la plupart des autres formats de sortie comme .mp4).

Cela gaspillera de la bande passante mais permet (théoriquement) un débit constant au bit prés sur l'ensemble du flux.

Pour rajouter des octets de bourrage (octets inutiles qui visent juste à avoir un débit strictement identique selon les vidéos), il suffit de rajouter les options -f mpegts -muxrate 4000K pour forcer le container MPEG-2 TS et un débit final (audio + vidéo) de 4000 Kb/s.

Si le débit muxrate est trop faible, vous aurez lors de l'encodage l'alerte [mpegts @ 0x562be5efa9c0] dts < pcr, TS is invalid mis en évidence par des couleurs vives.

Voici la ligne de commande que j'ai testé. Avec un débit vidéo de 2000 Kb/s et un débit audio de 128 Kb/s, un muxrate minimum de 2300 Kb/s est nécessaire pour ne pas avoir de problème.

ffmpeg -i "original.ts" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 2000k -minrate 2000k -maxrate 2000k -bufsize 2000k -c:a copy -f mpegts -muxrate 2300k "modif-720p.ts"

ffmpeg rajoute bien des octets de bourrage, cela se vérifie facilement en mettant un muxrate plus élevé.

Avec un muxrate 2300k, mon fichier vidéo fait 8,65 Mo, avec un muxrate 4600k, il fait 17,30 Mo soit exactement deux fois la taille grâce au bourrage supplémentaire.

Malheureusement, je vois que sur plusieurs fichiers de 30 secondes, j'ai un nombre d'octets qui n'est pas strictement le même, j'ai 68 Ko entre le plus grand fichier et le plus petit. Je suis déçus que le bourrage ne permettent pas d'avoir toujours exactement la même taille pour deux vidéos qui ont la même durée à l'image prés.

Si vous savez comment faire, je suis preneur.

vivien

  • Administrateur
  • *
  • Messages: 39 132
    • Twitter LaFibre.info
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #4 le: 13 septembre 2021 à 10:00:48 »
Je  continue les surprises.

J'ai encodé les mêmes fichiers sur deux PC différents et la taille est différente et surtout la durée après compression change de quelques dizaines de ms !

Dans les deux cas j'utilise ffmpeg version 4.3.2-0+deb11u1ubuntu1 avec using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2

Un PC avec 2 cœurs 4 threads et l'autre 4 cœurs 8 threads, j'imagine que c'est la cause des taille si différentes.

Les lignes de commande utilisées :


Le -muxrate 2300k qui était suffisant sur le PC 4 cœurs 8 threads est insuffisant sur le PC 2 cœurs, donc j'ai mis -muxrate 2400k pour les deux PC pour pouvoir comparer.

ffmpeg -i "Mozark-30s-2160p.ts" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 2000k -minrate 2000k -maxrate 2000k -bufsize 2000k -c:a copy -f mpegts -muxrate 2400k "Mozark-30s-720p.ts"
ffmpeg -i "ufc-30s-1080p.ts" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 2000k -minrate 2000k -maxrate 2000k -bufsize 2000k -c:a copy -f mpegts -muxrate 2400k "ufc-30s-720p.ts"
ffmpeg -i "gigalis-30s-1080p.ts" -filter:v "scale=1280:720" -pix_fmt yuv420p -c:v libx264 -preset veryslow -x264-params "nal-hrd=cbr:force-cfr=1" -b:v 2000k -minrate 2000k -maxrate 2000k -bufsize 2000k -c:a copy -f mpegts -muxrate 2400k "gigalis-30s-720p.ts"


Fichiers sources :
- Mozark-30s-2160p.ts : 30 sec 0ms
- ufc-30s-1080p.ts : 30 sec 0ms
- gigalis-30s-1080p.ts : 30 sec 0ms

PC 2 cœurs 4 threads :
- Mozark-30s-720p.ts : 30 sec 78ms - 9 024 564 octets
- ufc-30s-720p.ts : 30 sec 318ms - 9 098 260 octets
- gigalis-30s-720p.ts : 30 sec 59ms - 9 023 812 octets

PC 4 cœurs 8 threads :
- Mozark-30s-720p.ts : 30 sec 78ms - 9 024 564 octets
- ufc-30s-720p.ts : 30 sec 198ms - 9 065 548 octets
- gigalis-30s-720p.ts : 30 sec 59ms - 9 023 812 octets

Donc la durée peut changer pour un même fichier avec une même ligne d'encodage, selon le PC utilisé.

Tarkok

  • Client Orange Fibre
  • *
  • Messages: 134
  • Lille (59)
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #5 le: 13 septembre 2021 à 10:13:05 »
A mon avis ça dépend surtout de la méthode d'encodage utilisée :

- depuis le processeur sans accélération matérielle (entre Intel ou AMD il ne devrait pas y avoir trop de différence, ni entre les OS)
- depuis le processeur équipée d'un module d'encodage (module intel quick sync video sur processeurs Intel, je ne sais pas si AMD a un équivalent)
- depuis une carte graphique nvidia (NVENC)
- depuis une carte graphique AMD (OpenCL)

Selon l'encodage, chacun fait un peu à sa sauce.

EDIT : petite confusion sur le nom du module Intel.
« Modifié: 13 septembre 2021 à 10:35:04 par Tarkok »

vivien

  • Administrateur
  • *
  • Messages: 39 132
    • Twitter LaFibre.info
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #6 le: 13 septembre 2021 à 10:17:42 »
J'ai oublié de préciser, c'est du soft dans les deux cas et le système d’exploitation est Ubuntu 21.04 dans les deux cas.

PC 2 cœurs 4 threads :
- Intel Core i3-4150 @ 3.5 GHz
- GPU Intel HD Graphics 4400

PC 4 cœurs 8 threads :
- Intel Core i5-8250U @ 1.6 GHz
- GPU Intel UHD Graphics 620

Tarkok

  • Client Orange Fibre
  • *
  • Messages: 134
  • Lille (59)
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #7 le: 13 septembre 2021 à 10:33:28 »
A priori ces deux processeurs gèrent video quick sync, la différence est peut être dû à une évolution de la puce entre la génération 4 et la génération 8 chez Intel ?

Je ne sais pas si on peut totalement désactiver l'accélération matérielle dans le cas ou elle est gérée directement dans le processeur.

robin4002

  • Client Orange Fibre
  • *
  • Messages: 783
  • Illkirch (67) / Hattstatt (68)
FFmpeg: Encoder une vidéo H.264 en CBR (débit contant)
« Réponse #8 le: 13 septembre 2021 à 21:19:54 »
Chez AMD c'est VCE (Video Coding Engine) ou VCN (Video Core Next) pour les GPU après Raven Ridge.

Il n'y a pas d'accélération hardware des vidéos dans la partie CPU, ni chez AMD ni chez Intel.
Quick Sync Video d'Intel se trouve dans la partie GPU intégré à la plupart de ces processeurs, mais pas tous (ce n'ayant pas de GPU intégré ne l'ont logiquement pas).
Il n'y a aucune raison qu'elle soit utilisé lors d'un encodage purement CPU, il faut passer par des API spécifique pour l'utiliser.