Quoi? Un codec vidéo est un logiciel/matériel qui compresse et/ou décompresse la vidéo numérique.
Pour quoi? Malgré certaines limitations tant en termes de bande passante que
et en termes d'espace de stockage de données, le marché exige une qualité vidéo de plus en plus élevée. Vous souvenez-vous comment, dans le dernier article, nous avons calculé le minimum requis pour 30 images par seconde, 24 bits par pixel, avec une résolution de 480x240 ? Nous avons reçu 82,944 Mbit/s sans compression. La compression est actuellement le seul moyen de transmettre généralement de la HD/FullHD/4K sur les écrans de télévision et sur Internet. Comment y parvient-on ? Examinons maintenant brièvement les principales méthodes.
La traduction a été réalisée avec le soutien d'EDISON Software.
Une erreur courante que font les débutants est de confondre codec vidéo numérique et conteneur vidéo numérique. Un conteneur est un certain format. Un wrapper contenant des métadonnées vidéo (et éventuellement audio). La vidéo compressée peut être considérée comme une charge utile de conteneur.
Généralement, l'extension d'un fichier vidéo indique son type de conteneur. Par exemple, le fichier video.mp4 est probablement un conteneur MPEG-4 Partie 14, et un fichier nommé video.mkv est très probablement matriochka. Pour être complètement sûr du codec et du format du conteneur, vous pouvez utiliser FFmpeg ou MediaInfo.
Un peu d'histoire
Avant d'arriver à Comment?, plongeons un peu dans l'histoire pour mieux comprendre certains codecs plus anciens.
Codec vidéo H.261 est apparu en 1990 (techniquement - en 1988) et a été créé pour fonctionner à un taux de transfert de données de 64 Kbps. Il utilisait déjà des idées telles que le sous-échantillonnage des couleurs, les macroblocs, etc. La norme du codec vidéo a été publiée en 1995 H.263, qui s'est développé jusqu'en 2001.
La première version a été achevée en 2003 H.264 / AVC. La même année, TrueMotion a lancé son codec vidéo gratuit avec perte appelé VP3. Google a racheté l'entreprise en 2008, libérant VP8 la même année. En décembre 2012, Google a publié VP9, et il est pris en charge dans environ les ¾ du marché des navigateurs (y compris les appareils mobiles).
AV1 est un nouveau codec vidéo gratuit et open source développé par Alliance pour les médias ouverts (AOMédias), qui comprend les entreprises les plus connues, telles que : Google, Mozilla, Microsoft, Amazon, Netflix, AMD, ARM, NVidia, Intel et Cisco. La première version du codec, 0.1.0, a été publiée le 7 avril 2016.
Naissance d'AV1
Début 2015, Google travaillait sur VP10Xiph (qui appartient à Mozilla) travaillait sur Daala, et Cisco a créé son propre codec vidéo gratuit appelé Thor.
Puis MPEG LA premières limites annuelles annoncées pour HEVC (H.265) et des frais 8 fois plus élevés que pour le H.264, mais ils ont rapidement modifié à nouveau les règles :
pas de limite annuelle,
frais de contenu (0,5 % des revenus) et
les frais unitaires sont environ 10 fois supérieurs à ceux du H.264.
Alliance pour les médias ouverts a été créé par des entreprises de différents domaines : équipementiers (Intel, AMD, ARM, Nvidia, Cisco), fournisseurs de contenu (Google, Netflix, Amazon), créateurs de navigateurs (Google, Mozilla) et autres.
Les sociétés avaient un objectif commun : un codec vidéo libre de droits. Apparaît alors AV1 avec une licence de brevet beaucoup plus simple. Timothy B. Terryberry a fait une présentation époustouflante qui est devenue l'origine du concept AV1 actuel et de son modèle de licence.
Vous serez surpris de savoir que vous pouvez analyser le codec AV1 via un navigateur (les personnes intéressées peuvent se rendre sur aomanalyzer.org).
Codec universel
Examinons les principaux mécanismes qui sous-tendent le codec vidéo universel. La plupart de ces concepts sont utiles et sont utilisés dans les codecs modernes tels que VP9, AV1 и HEVC. Je vous préviens que beaucoup de choses expliquées seront simplifiées. Parfois, des exemples concrets (comme avec H.264) seront utilisés pour démontrer la technologie.
1ère étape - diviser l'image
La première étape consiste à diviser le cadre en plusieurs sections, sous-sections et au-delà.
Pour quoi? Il y a plusieurs raisons. Lorsque nous divisons une image, nous pouvons prédire plus précisément le vecteur de mouvement en utilisant de petites sections pour les petites pièces mobiles. Alors que pour un arrière-plan statique vous pouvez vous limiter à des sections plus grandes.
Les codecs organisent généralement ces sections en sections (ou morceaux), macroblocs (ou blocs d'arborescence de codage) et plusieurs sous-sections. La taille maximale de ces partitions varie, HEVC la définit sur 64x64 tandis qu'AVC utilise 16x16, et les sous-partitions peuvent être divisées jusqu'à 4x4.
Vous souvenez-vous des types de cadres du dernier article ?! La même chose peut être appliquée aux blocs, nous pouvons donc avoir un fragment I, un bloc B, un macrobloc P, etc.
Pour ceux qui veulent s’entraîner, observez comment l’image est divisée en sections et sous-sections. Pour ce faire, vous pouvez utiliser celui déjà évoqué dans l’article précédent. Analyseur Intel Video Pro (celui qui est payant, mais avec une version d'essai gratuite limitée aux 10 premières images). Sections analysées ici VP9:
2ème étape - prévision
Une fois que nous avons des sections, nous pouvons leur faire des prévisions astrologiques. Pour Prévisions INTER doit être transféré vecteurs de mouvement et le reste, et pour la prévision INTRA, il est transmis direction des prévisions et le reste.
3ème étape - transformation
Une fois que l'on dispose d'un bloc résiduel (section prédite → section réelle), il est possible de le transformer de telle manière que l'on sache quels pixels peuvent être écartés tout en conservant la qualité globale. Certaines transformations fournissent le comportement exact.
Bien qu’il existe d’autres méthodes, examinons-les plus en détail. transformée en cosinus discrète (DCT - à partir de transformée en cosinus discrète). Principales fonctions du DCT :
Convertit des blocs de pixels en blocs de coefficients de fréquence de taille égale.
Condense la puissance pour aider à éliminer la redondance spatiale.
Fournit la réversibilité.
2 février 2017 Sintra R.J. (Cintra, RJ) et Bayer F.M. (Bayer FM) a publié un article sur une transformation de type DCT pour la compression d'images qui ne nécessite que 14 ajouts.
Ne vous inquiétez pas si vous ne comprenez pas les avantages de chaque point. Utilisons maintenant des exemples spécifiques pour voir leur vraie valeur.
Prenons ce bloc de pixels de 8x8 :
Ce bloc est rendu dans l'image suivante de 8 x 8 pixels :
Appliquez DCT à ce bloc de pixels et obtenez un bloc de coefficients 8x8 :
Et si on rend ce bloc de coefficients, on obtiendra l'image suivante :
Comme vous pouvez le constater, cela ne ressemble pas à l'image originale. Vous voyez que le premier coefficient est très différent de tous les autres. Ce premier coefficient est connu sous le nom de coefficient DC, qui représente tous les échantillons du tableau d'entrée, un peu comme une moyenne.
Ce bloc de coefficients a une propriété intéressante : il sépare les composantes hautes fréquences des composantes basses fréquences.
Dans une image, la majeure partie de la puissance est concentrée aux fréquences inférieures. Ainsi, si vous convertissez l'image en composantes de fréquence et supprimez les coefficients de fréquence plus élevés, vous pouvez réduire la quantité de données nécessaires pour décrire l'image sans trop sacrifier la qualité de l'image.
La fréquence fait référence à la rapidité avec laquelle le signal change.
Essayons d'appliquer les connaissances acquises dans le cas de test en convertissant l'image originale en sa fréquence (bloc de coefficients) à l'aide de DCT, puis en supprimant une partie des coefficients les moins importants.
Nous le convertissons d’abord dans le domaine fréquentiel.
Ensuite, on écarte une partie (67 %) des coefficients, principalement la partie inférieure droite.
Enfin, nous reconstruisons l'image à partir de ce bloc de coefficients rejeté (rappelez-vous, il doit être inversible) et la comparons à l'original.
Nous voyons qu'elle ressemble à l'image originale, mais il existe de nombreuses différences par rapport à l'original. Nous avons jeté 67,1875 % et avons toujours obtenu quelque chose qui ressemble à l'original. Il était possible d'écarter les coefficients de manière plus réfléchie pour obtenir une image de qualité encore meilleure, mais c'est un sujet suivant.
Chaque coefficient est généré en utilisant tous les pixels
Important : chaque coefficient n'est pas directement mappé à un pixel, mais constitue une somme pondérée de tous les pixels. Ce graphique étonnant montre comment les premier et deuxième coefficients sont calculés à l'aide de poids uniques à chaque indice.
Vous pouvez également essayer de visualiser le DCT en regardant une formation d'image simple basée sur celui-ci. Par exemple, voici le symbole A généré en utilisant chaque coefficient de pondération :
4ème étape - quantification
Après avoir rejeté certains coefficients à l'étape précédente, à la dernière étape (transformation), nous effectuons une forme spéciale de quantification. A ce stade, il est acceptable de perdre des informations. Ou, plus simplement, on quantifiera les coefficients pour réaliser la compression.
Comment quantifier un bloc de coefficients ? L'une des méthodes les plus simples est la quantification uniforme, lorsque nous prenons un bloc, le divisons par une valeur (par 10) et arrondissons le résultat.
Peut-on inverser ce bloc de coefficients ? Oui, nous pouvons le faire en multipliant par la même valeur par laquelle nous avons divisé.
Cette approche n’est pas la meilleure car elle ne prend pas en compte l’importance de chaque coefficient. On pourrait utiliser une matrice de quantificateurs au lieu d'une valeur unique, et cette matrice pourrait exploiter la propriété DCT en quantifiant la majorité du coin inférieur droit et la minorité du coin supérieur gauche.
Étape 5 - codage entropique
Une fois que nous avons quantifié les données (blocs d’images, fragments, images), nous pouvons toujours les compresser sans perte. Il existe de nombreuses façons algorithmiques de compresser des données. Nous allons jeter un coup d'œil rapide à certains d'entre eux. Pour une compréhension plus approfondie, vous pouvez lire le livre Understanding Compression: Data Compression for Modern Developers ("Comprendre la compression : compression de données pour les développeurs modernes»).
Encodage vidéo avec VLC
Disons que nous avons un flux de personnages : a, e, r и t. La probabilité (allant de 0 à 1) de la fréquence à laquelle chaque caractère apparaît dans un flux est présentée dans ce tableau.
a
e
r
t
Probabilité
0,3
0,3
0,2
0,2
Nous pouvons attribuer des codes binaires uniques (de préférence petits) aux plus probables, et des codes plus grands aux moins probables.
a
e
r
t
Probabilité
0,3
0,3
0,2
0,2
Code binaire
0
10
110
1110
Nous compressons le flux, en supposant que nous finirons par dépenser 8 bits pour chaque caractère. Sans compression, 24 bits seraient nécessaires par caractère. Si vous remplacez chaque caractère par son code, vous faites des économies !
La première étape consiste à encoder le caractère e, qui est égal à 10, et le deuxième caractère est a, auquel on ajoute (pas de manière mathématique) : [10][0], et enfin le troisième caractère t, ce qui rend notre flux binaire compressé final égal à [10][0][1110] ou 1001110, qui ne nécessite que 7 bits (3,4 fois moins d'espace que l'original).
Veuillez noter que chaque code doit être un code unique avec un préfixe. Algorithme de Huffman vous aidera à trouver ces numéros. Bien que cette méthode ne soit pas sans défauts, il existe des codecs vidéo qui proposent toujours cette méthode algorithmique de compression.
Le codeur et le décodeur doivent avoir accès à une table de symboles avec leurs codes binaires. Par conséquent, il est également nécessaire d’envoyer un tableau en entrée.
Codage arithmétique
Disons que nous avons un flux de personnages : a, e, r, s и t, et leur probabilité est présentée dans ce tableau.
a
e
r
s
t
Probabilité
0,3
0,3
0,15
0,05
0,2
A l'aide de ce tableau, nous allons construire des plages contenant tous les caractères possibles, triés par le plus grand nombre.
Encodons maintenant un flux de trois caractères : manger.
Sélectionnez d'abord le premier caractère e, qui est compris entre 0,3 et 0,6 (non compris). Nous prenons cette sous-gamme et la divisons à nouveau dans les mêmes proportions que précédemment, mais pour cette nouvelle gamme.
Continuons à coder notre flux manger. Maintenant, prenons le deuxième personnage a, qui se situe dans la nouvelle sous-plage de 0,3 à 0,39, puis prenons notre dernier caractère t et en répétant à nouveau le même processus, nous obtenons la sous-plage finale de 0,354 à 0,372.
Il suffit de sélectionner un nombre dans la dernière sous-plage de 0,354 à 0,372. Choisissons 0,36 (mais vous pouvez choisir n'importe quel autre nombre dans cette sous-plage). Ce n'est qu'avec ce numéro que nous pourrons restaurer notre flux d'origine. C'est comme si nous tracions une ligne entre les plages pour coder notre flux.
L'opération inverse (c'est-à-dire décodage) est tout aussi simple : avec notre nombre 0,36 et notre fourchette initiale, nous pouvons exécuter le même processus. Mais maintenant, grâce à ce numéro, nous identifions le flux encodé à l'aide de ce numéro.
Avec la première plage, on remarque que notre numéro correspond à la tranche, c'est donc notre premier caractère. Maintenant, nous divisons à nouveau cette sous-gamme en suivant le même processus que précédemment. Ici vous pouvez voir que 0,36 correspond au symbole a, et après avoir répété le processus, nous sommes arrivés au dernier caractère t (formant notre flux codé original manger).
L'encodeur et le décodeur doivent avoir un tableau de probabilités de symboles, il est donc nécessaire de l'envoyer également dans les données d'entrée.
Plutôt élégant, n'est-ce pas ? Celui qui a proposé cette solution était sacrément intelligent. Certains codecs vidéo utilisent cette technique (ou du moins la proposent en option).
L’idée est de compresser sans perte un flux binaire quantifié. Il manque sûrement à cet article des tonnes de détails, de raisons, de compromis, etc. Mais si vous êtes développeur, vous devriez en savoir plus. Les nouveaux codecs tentent d'utiliser différents algorithmes de codage entropique tels que ANS.
Étape 6 - format de flux binaire
Après avoir fait tout cela, il ne reste plus qu'à décompresser les images compressées dans le cadre des étapes effectuées. Le décodeur doit être explicitement informé des décisions prises par l'encodeur. Le décodeur doit être fourni avec toutes les informations nécessaires : profondeur de bits, espace colorimétrique, résolution, informations de prédiction (vecteurs de mouvement, prédiction INTER directionnelle), profil, niveau, fréquence d'images, type d'image, numéro d'image et bien plus encore.
Nous allons jeter un coup d'œil rapide au bitstream H.264. Notre première étape consiste à créer un flux binaire H.264 minimal (FFmpeg ajoute par défaut toutes les options d'encodage telles que SEINAL — nous découvrirons ce que c'est un peu plus loin). Nous pouvons le faire en utilisant notre propre référentiel et FFmpeg.
Cette commande générera un bitstream brut H.264 avec une image, résolution 64×64, avec espace colorimétrique YUV420. Dans ce cas, l'image suivante est utilisée comme cadre.
Flux binaire H.264
Norme AVC (H.264) détermine que les informations seront envoyées dans des macrotrames (au sens réseau), appelées NAL (il s'agit d'un niveau d'abstraction du réseau). L'objectif principal de NAL est de fournir une présentation vidéo « adaptée au Web ». Cette norme devrait fonctionner sur les téléviseurs (basé sur le flux) et sur Internet (basé sur les paquets).
Il existe un marqueur de synchronisation pour définir les limites des éléments NAL. Chaque jeton de synchronisation contient une valeur 0x00 0x00 0x01, sauf le tout premier, qui est égal à 0x00 0x00 0x00 0x01. Si nous lançons vidage hexagonal pour le flux binaire H.264 généré, nous identifions au moins trois modèles NAL au début du fichier.
Comme indiqué, le décodeur doit connaître non seulement les données de l'image, mais également les détails de la vidéo, l'image, les couleurs, les paramètres utilisés et bien plus encore. Le premier octet de chaque NAL définit sa catégorie et son type.
Identificateur de type NAL
description
0
еизвестный тип
1
Fragment d'image codé sans IDR
2
Section de données de tranche codées A
3
Section de données de tranche codées B
4
Section de données de tranche codées C
5
Fragment IDR codé d'une image IDR
6
Plus d'informations sur l'extension SEI
7
Ensemble de paramètres de séquence SPS
8
Ensemble de paramètres d'image PPS
9
Séparateur d'accès
10
Fin de séquence
11
Fin du fil
...
...
Généralement, le premier NAL d'un flux binaire est PLC. Ce type de NAL est chargé d'informer sur les variables d'encodage communes telles que le profil, le niveau, la résolution, etc.
Si nous sautons le premier marqueur de synchronisation, nous pouvons décoder le premier octet pour savoir quel type NAL est le premier.
Par exemple, le premier octet après le jeton de synchronisation est 01100111, où le premier bit (0) est dans le champ forbidden_zero_bit. 2 bits suivants (11) nous indique le champ nal_ref_idc, qui indique si ce NAL est un champ de référence ou non. Et les 5 bits restants (00111) nous indique le champ nal_unit_type, dans ce cas c'est le bloc SPS (7)NAL.
Deuxième octet (binaire=01100100, hex=Assistance , déc=100) dans SPS NAL est le champ profil_idc, qui montre le profil utilisé par l'encodeur. Dans ce cas, un profil haut limité a été utilisé (c'est-à-dire un profil haut sans support bidirectionnel du segment B).
Si vous regardez la spécification bitstream H.264 pour SPS NAL, nous trouverons de nombreuses valeurs pour le nom du paramètre, la catégorie et la description. Par exemple, regardons les champs pic_width_in_mbs_minus_1 и pic_height_in_map_units_minus_1.
Le nom du paramètre
catégorie
description
pic_width_in_mbs_minus_1
0
eu(v)
pic_height_in_map_units_minus_1
0
eu(v)
Si nous effectuons quelques opérations mathématiques avec les valeurs de ces champs, nous obtiendrons une résolution. On peut représenter 1920 x 1080 en utilisant pic_width_in_mbs_minus_1 avec une valeur de 119 ((119 + 1) * macroblock_size = 120 * 16 = 1920). Encore une fois, pour gagner de la place, au lieu de coder 1920, nous l'avons fait avec 119.
Si nous continuons à vérifier notre vidéo créée sous forme binaire (par exemple : xxd -b -c 11v/minimal_yuv420.h264), vous pouvez alors accéder au dernier NAL, qui est la trame elle-même.
Ici, nous voyons ses 6 premiers octets : 01100101 10001000 10000100 00000000 00100001 11111111. Puisque le premier octet est connu pour indiquer le type NAL, dans ce cas (00101) est un fragment IDR (5), et vous pouvez ensuite l'explorer davantage :
En utilisant les informations de spécification, il sera possible de décoder le type de fragment (type_tranche) et le numéro de cadre (num_cadre) parmi d'autres domaines importants.
Pour obtenir les valeurs de certains champs (ue(v), me(v), se(v) Ou te(v)), nous devons décoder le fragment à l'aide d'un décodeur spécial basé sur code Golomb exponentiel. Cette méthode est très efficace pour encoder des valeurs de variables, notamment lorsqu'il existe de nombreuses valeurs par défaut.
Les valeurs type_tranche и num_cadre de cette vidéo sont 7 (fragment I) et 0 (première image).
Un bitstream peut être considéré comme un protocole. Si vous souhaitez en savoir plus sur le bitstream, vous devez vous référer à la spécification UIT H.264. Voici un macro-diagramme montrant où se trouvent les données d'image (YUV sous forme compressée).
D'autres flux binaires peuvent être examinés, tels que VP9, H.265 (HEVC) ou même notre nouveau meilleur bitstream AV1. Sont-ils tous semblables ? Non, mais une fois qu’on en comprend au moins un, il est beaucoup plus facile de comprendre le reste.
Envie de pratiquer ? Explorez le flux binaire H.264
Vous pouvez générer une vidéo à image unique et utiliser MediaInfo pour examiner le flux binaire H.264. En fait, rien ne vous empêche même de consulter le code source qui analyse le flux binaire H.264 (AVC).
Pour vous entraîner, vous pouvez utiliser Intel Video Pro Analyzer (ai-je déjà dit que le programme est payant, mais il existe une version d'essai gratuite avec une limite de 10 images ?).
vue d'ensemble
Notez que de nombreux codecs modernes utilisent le même modèle que celui que nous venons d'étudier. Ici, jetons un coup d'œil au schéma fonctionnel du codec vidéo Thor. Il contient toutes les étapes que nous avons parcourues. Tout l’intérêt de cet article est au moins de vous permettre de mieux comprendre les innovations et la documentation dans ce domaine.
Auparavant, il avait été calculé que 139 Go d'espace disque seraient nécessaires pour stocker un fichier vidéo d'une durée d'une heure en qualité 720p et 30 ips. Si vous utilisez les méthodes abordées dans cet article (prédictions inter-images et internes, transformation, quantification, codage entropique, etc.), vous pouvez alors obtenir (sur la base du fait que nous dépensons 0,031 bits par pixel) une vidéo d'assez qualité satisfaisante, occupant seulement 367,82 Mo, et non 139 Go de mémoire.
Comment le H.265 obtient-il un meilleur taux de compression que le H.264 ?
Maintenant que nous en savons plus sur le fonctionnement des codecs, il est plus facile de comprendre comment les codecs les plus récents peuvent offrir des résolutions plus élevées avec moins de bits.
Si vous comparez AVC и HEVC, il convient de rappeler qu'il s'agit presque toujours d'un choix entre une charge CPU et un taux de compression plus élevés.
HEVC a plus d'options de section (et de sous-section) que AVC, davantage de directions de prédiction internes, un codage entropique amélioré, etc. Toutes ces améliorations ont été apportées H.265 capable de comprimer 50 % de plus que H.264.