Fonctionnement du codec vidéo. Partie 2. Quoi, pourquoi, comment

Partie I: notions de base sur la vidéo et l'image




L'histoire de Kodek

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 en termes de bande passante,
et en termes d'espace de stockage, le marché a besoin de plus en plus de vidéo de haute qualité. Rappelez-vous comment dans le dernier article, nous avons calculé le minimum nécessaire pour 30 images par seconde, 24 bits par pixel, avec une résolution de 480x240? Reçu 82,944 Mbps sans compression. La compression est le seul moyen de transférer HD / FullHD / 4K vers les écrans de télévision et Internet. Comment y parvient-on? Nous allons maintenant examiner brièvement les principales méthodes.
Logiciel EDISON - développement web
La traduction a été réalisée avec le soutien d'EDISON Software.

Nous sommes engagés dans l' intégration de systèmes de vidéosurveillance , ainsi que dans le développement d'un microtomographe .

Codec vs Container


Une erreur courante pour les novices est de confondre un codec vidéo numérique et un 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.

En règle générale, une extension de fichier vidéo indique un type de conteneur. Par exemple, le fichier video.mp4 est très probablement un conteneur MPEG-4 Part 14 , et le fichier nommé video.mkv est très probablement une poupée russe. Pour être totalement sûr du codec et du format de conteneur, vous pouvez utiliser FFmpeg ou MediaInfo .

Un peu d'histoire


Avant d'arriver à Comment? , plongeons dans un peu d'histoire pour mieux comprendre certains anciens codecs.

Le codec vidéo H.261 est apparu en 1990 (techniquement - en 1988) et a été créé pour fonctionner avec un taux de transfert de données de 64 Kbps. Il a déjà utilisé des idées telles que le sous-échantillonnage des couleurs, les macroblocs, etc. En 1995, la norme de codec vidéo H.263 a été publiée, qui s'est développée jusqu'en 2001.

En 2003, la première version de H.264 / AVC a été achevée. La même année, TrueMotion a publié son codec vidéo gratuit qui compresse la vidéo avec perte appelée VP3 . En 2008, Google a acheté cette société, 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 open source gratuit développé par l'Open Media Alliance ( AOMedia ), qui comprend des sociétés bien 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 a travaillé sur VP10 , Xiph (qui appartient à Mozilla) a travaillé sur Daala , et Cisco a créé son codec vidéo gratuit appelé Thor .

Ensuite, MPEG LA a d' abord annoncé des limites annuelles pour HEVC ( H.265 ) et des frais 8 fois plus élevés que pour H.264, mais ils ont bientôt changé les règles à nouveau:

pas de limite annuelle,
frais de contenu (0,5% du chiffre d'affaires) et
les coûts unitaires sont environ 10 fois plus élevés que pour le H.264.

L'Open Media Alliance a été créée par des entreprises de divers domaines: fabricants d'équipements (Intel, AMD, ARM, Nvidia, Cisco), fournisseurs de contenu (Google, Netflix, Amazon), fabricants de navigateurs (Google, Mozilla) et autres.

Les entreprises avaient un objectif commun: un codec vidéo sans redevances. Vient ensuite AV1 avec une licence de brevet beaucoup plus simple. Timothy B. Terriberry a fait une présentation étonnante, qui est devenue la source du concept actuel d'AV1 et de son modèle de licence.

Vous serez surpris d'apprendre que vous pouvez analyser le codec AV1 via un navigateur (les personnes intéressées peuvent aller sur aomanalyzer.org ).

image

Codec universel


Analysons les mécanismes de base qui sous-tendent le codec vidéo universel. La plupart de ces concepts sont utiles et utilisés dans les codecs modernes tels que VP9 , AV1 et HEVC . Je vous préviens que beaucoup de choses expliquées seront simplifiées. Des exemples concrets seront parfois utilisés (comme c'est le cas avec H.264) pour démontrer la technologie.

1ère étape - fractionnement de l'image


La première étape consiste à diviser le cadre en plusieurs sections, sous-sections, etc.

image

Pour quoi? Il y a plusieurs raisons. Lorsque nous divisons l'image, nous pouvons prédire plus précisément le vecteur de mouvement à l'aide 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.

En règle générale, les codecs organisent ces sections en sections (ou fragments), macroblocs (ou blocs d'une arborescence de codage) et de nombreuses sous-sections. La taille maximale de ces partitions varie, HEVC définit 64x64, tandis qu'AVC utilise 16x16, et les sous-sections peuvent être divisées en 4x4.

Rappelez-vous les variétés 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, regardez comment l'image sera divisée en sections et sous-sections. Pour ce faire, vous pouvez utiliser Intel Video Pro Analyzer déjà mentionné dans l'article précédent (celui qui est payé, mais avec une version d'essai gratuite, qui a une limite sur les 10 premières images). Les sections de VP9 sont analysées ici:

image

2e étape - prévision


Dès que nous avons des sections, nous pouvons y faire des prévisions astrologiques . Pour la prédiction INTER, il est nécessaire de transférer les vecteurs de mouvement et le reste, et pour la prédiction INTRA, la direction de la prévision et le reste sont transmis.

3e étape - conversion


Après avoir obtenu le bloc résiduel (la section prédite → la section réelle), il est possible de le transformer de manière à savoir quels pixels peuvent être supprimés, tout en conservant la qualité globale. Certaines transformations fournissent un comportement précis.

Bien qu'il existe d'autres méthodes, considérons plus en détail la transformée en cosinus discrète ( DCT - à partir de la transformée en cosinus discrète ). Caractéristiques clés de DCT:

  • Convertit des blocs de pixels en blocs de coefficients de fréquence de taille égale.
  • Scelle l'alimentation, contribuant à éliminer la redondance spatiale.
  • Assure la réversibilité.

2 février 2017 Sintra R.J. (Cintra, RJ) et Bayer F.M. (Bayer FM) a publié un article sur la conversion de type DCT pour la compression d'image, ne nécessitant que 14 ajouts.

Ne vous inquiétez pas si vous ne comprenez pas les avantages de chaque article. Maintenant, avec des exemples concrets, nous allons vérifier leur valeur réelle.

Prenons un bloc de 8x8 pixels comme celui-ci:

image

Ce bloc est rendu dans l'image suivante 8 par 8 pixels:

image

Appliquez DCT à ce bloc de pixels et obtenez un bloc de coefficients de taille 8x8:

image

Et si nous rendons ce bloc de coefficients, nous obtenons l'image suivante:

image

Comme vous pouvez le voir, cela ne ressemble pas à l'image d'origine. Vous remarquerez peut-être que le premier coefficient est très différent de tous les autres. Ce premier coefficient est connu sous le nom de coefficient DC représentant tous les échantillons du tableau d'entrée, quelque chose de similaire à la valeur moyenne.

Ce bloc de coefficients a une propriété intéressante: il sépare les composants haute fréquence de ceux basse fréquence.

image

Dans l'image, la majeure partie de la puissance est concentrée à des fréquences plus basses.Par conséquent, si vous convertissez l'image en ses 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 sacrifier trop la qualité de l'image.
La fréquence signifie à quelle vitesse le signal change.
Essayons d'appliquer les connaissances acquises dans l'exemple de test en convertissant l'image d'origine à sa fréquence (bloc de coefficients) à l'aide de DCT, puis en supprimant certains des coefficients les moins importants.

Tout d'abord, convertissez-le dans le domaine fréquentiel.

image

Ensuite, nous éliminons une partie (67%) des coefficients, principalement le côté inférieur droit.

image

Enfin, nous restaurons l'image à partir de ce bloc de coefficients rejeté (rappelez-vous, elle doit être réversible) et comparons avec l'original.

image

Nous voyons qu'elle ressemble à l'image d'origine, mais il existe de nombreuses différences par rapport à l'original. Nous avons lancé 67,1875% et avons toujours obtenu quelque chose qui ressemble à la source d'origine. Vous pouvez plus délibérément supprimer les coefficients pour obtenir une image de qualité encore meilleure, mais c'est le sujet suivant.

Chaque coefficient est généré en utilisant tous les pixels.



Important: chaque coefficient n'est pas directement affiché sur un pixel, mais est une somme pondérée de tous les pixels. Ce graphique étonnant montre comment les premier et deuxième coefficients sont calculés en utilisant des poids uniques à chaque indice.

image

Vous pouvez également essayer de visualiser le DCT en regardant une imagerie simple basée sur celui-ci. Par exemple, voici le symbole A généré en utilisant chaque poids de coefficient:

image


4ème étape - quantification


Après avoir jeté quelques coefficients à l'étape précédente, à la dernière étape (transformation), nous produisons une forme de quantification spéciale. À ce stade, il est permis de perdre des informations. Ou, plus simplement, nous quantifierons les coefficients pour réaliser la compression.

Comment quantifier un bloc de coefficients? L'une des méthodes les plus simples sera la quantification uniforme, lorsque nous prenons un bloc, le divisons par une valeur (par 10) et arrondissons ce qui s'est passé.

image

Pouvons-nous inverser ce bloc de coefficients? Oui, nous pouvons, en multipliant par la même valeur que nous avons divisée par.

image

Cette approche n'est pas la meilleure, car elle ne prend pas en compte l'importance de chaque coefficient. On pourrait utiliser la matrice de quantification au lieu d'une seule valeur, et cette matrice pourrait utiliser la propriété DCT, quantifiant la majeure partie du coin inférieur droit et une minorité du coin supérieur gauche.

5 étapes - codage entropique


Après avoir quantifié les données (blocs d'images, fragments, cadres), nous pouvons toujours les compresser sans perte. Il existe de nombreuses méthodes algorithmiques pour compresser les données. Nous allons brièvement vous familiariser avec certains d'entre eux, pour une compréhension plus approfondie, vous pouvez lire le livre " Comprendre la compression: compression de données pour les développeurs modernes " (" Comprendre la compression: compression de données pour les développeurs modernes ").

Encodage vidéo avec VLC


Supposons que nous ayons un flux de caractères: a , e , r et t . La probabilité (allant de 0 à 1) de la fréquence à laquelle chaque symbole apparaît dans le flux est présentée dans ce tableau.
unert
Probabilité0,30,30,20,2
Nous pouvons attribuer des codes binaires uniques (de préférence petits) aux codes les plus probables, et les plus grands moins probables.
unert
Probabilité0,30,30,20,2
Code binaire0101101110
Nous compressons le flux, en supposant qu'à la fin nous dépensons 8 bits pour chaque caractère. Sans compression sur un caractère, 24 bits seraient nécessaires. Si chaque caractère est remplacé par son code, nous réalisons des économies!

La première étape consiste à coder le caractère e , qui est 10, et le deuxième caractère est a , qui est ajouté (pas mathématiquement): [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 dans l'original).

Veuillez noter que chaque code doit être un code unique avec un préfixe. L'algorithme de Huffman vous aidera à trouver ces nombres. Bien que cette méthode ne soit pas sans défauts, il existe des codecs vidéo qui offrent toujours cette méthode algorithmique de compression.

L'encodeur et le décodeur doivent avoir accès à la table des symboles avec leurs codes binaires. Par conséquent, il est également nécessaire d'envoyer une table en entrée.

Codage arithmétique


Supposons que nous ayons un flux de caractères: a , e , r , s et t , et leur probabilité est représentée par ce tableau.
unerst
Probabilité0,30,30,150,050,2
Avec ce tableau, nous construisons des plages contenant tous les caractères possibles, triées par le plus grand nombre.

image

Maintenant, codons un flux de trois caractères: manger .

Tout d'abord, sélectionnez le premier caractère e , qui se situe dans la sous-plage de 0,3 à 0,6 (non compris). On reprend cette sous-gamme et on la divise à nouveau dans les mêmes proportions qu'avant, mais déjà pour cette nouvelle gamme.

image

Continuons à coder notre flux de manger . Maintenant, nous prenons le deuxième symbole a , qui est dans la nouvelle sous-gamme de 0,3 à 0,39, puis nous prenons notre dernier symbole t et, en répétant le même processus à nouveau, nous obtenons la dernière sous-gamme de 0,354 à 0,372.

image

Nous avons juste besoin 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 nombre que nous pouvons restaurer notre flux d'origine. C'est comme si nous dessinions une ligne à l'intérieur des plages pour encoder notre flux.

image

L'opération inverse (c'est-à-dire le décodage ) est tout aussi simple: avec notre nombre 0,36 et notre plage initiale, nous pouvons démarrer le même processus. Mais maintenant, en utilisant ce numéro, nous révélons le flux encodé en utilisant ce numéro.

Avec la première plage, nous remarquons que notre nombre correspond à une tranche, c'est donc notre premier caractère. Encore une fois, nous partageons cette sous-bande, effectuant le même processus que précédemment. Ici, vous pouvez voir que 0,36 correspond au caractère a , et après avoir répété le processus, nous arrivons au dernier caractère t (formant notre flux codé d'origine eat ).

Le codeur et le décodeur doivent tous deux avoir une table de probabilités de symboles, il est donc nécessaire de l'envoyer dans les données d'entrée.

Assez élégant, non? Quelqu'un qui a trouvé cette solution était sacrément intelligent. Certains codecs vidéo utilisent cette technique (ou, dans tous les cas, la proposent en option).

L'idée est de compresser un train de bits quantifié sans perte. Certes, dans cet article, il n'y a pas de tonnes de détails, de raisons, de compromis, etc. Mais vous, si vous êtes développeur, devez en savoir plus. De nouveaux codecs essaient d'utiliser différents algorithmes de codage entropique, tels que ANS .

6 étapes - format bitstream


Après avoir fait tout cela, il reste à décompresser les trames compressées dans le cadre des étapes franchies. Le décodeur doit être explicitement informé des décisions prises par le codeur. Le décodeur doit être fourni avec toutes les informations nécessaires: profondeur de bits, espace colorimétrique, résolution, informations sur les prévisions (vecteurs de mouvement, prédiction INTER directionnelle), profil, niveau, fréquence d'images, type de trame, numéro de trame et bien plus encore.

Nous allons jeter un œil au flux binaire H.264 . Notre première étape consiste à créer un flux binaire H.264 minimum (FFmpeg ajoute par défaut tous les paramètres d'encodage, tels que SEI NAL - un peu plus loin, nous découvrirons ce que c'est). Nous pouvons le faire en utilisant notre propre référentiel et FFmpeg.

./s/ffmpeg -i /files/i/minimal.png -pix_fmt yuv420p /files/v/minimal_yuv420.h264

Cette commande va générer un train de bits H.264 brut avec une trame, résolution 64x64, avec l'espace colorimétrique YUV420 . L'image suivante est utilisée comme cadre.

image

Flux binaire H.264


La norme AVC ( H.264 ) définit que les informations seront envoyées dans des macro-trames (dans la compréhension du réseau) appelées NAL (c'est un tel niveau d'abstraction du réseau). L'objectif principal de NAL est de fournir une présentation vidéo «conviviale». Cette norme devrait fonctionner sur les téléviseurs (basés sur les flux), sur Internet (basés sur les packages).

image

Il existe un marqueur de synchronisation pour définir les limites des éléments NAL. Chaque marqueur de synchronisation contient la valeur 0x00 0x00 0x01, à l'exception du tout premier, qui est 0x00 0x00 0x00 0x01. Si nous exécutons hexdump pour le flux binaire H.264 généré, nous identifierons au moins trois modèles NAL au début du fichier.

image

Comme indiqué, le décodeur doit connaître non seulement les données d'image, mais aussi les détails de la vidéo, la trame, la couleur, 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 NALLa description
0Type inconnu
1Fragment d'image codé sans IDR
2Section de données de la tranche codée A
3Section B des données sur les tranches codées
4Section de données de tranche codée C
5Fragment IDR codé d'une image IDR
6Informations supplémentaires sur l'extension SEI
7Ensemble de paramètres de séquence SPS
8Ensemble de paramètres d'image PPS
9Délimiteur d'accès
10Fin de séquence
11Fin du flux
......
Habituellement, le premier flux binaire NAL est SPS . Ce type de NAL est chargé de signaler les variables de codage courantes, telles que le profil, le niveau, la résolution, etc.

Si nous sautons le premier jeton de synchronisation, nous pouvons décoder le premier octet pour savoir quel type de NAL est le premier.

Par exemple, le premier octet après le marqueur de synchronisation est 01100111 , où le premier bit ( 0 ) est dans le champ f orbidden_zero_bit . Les 2 bits suivants ( 11 ) nous indiquent 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 indiquent le champ nal_unit_type, dans ce cas il s'agit d'un bloc NAL SPS ( 7 ).

Le deuxième octet ( binaire = 01100100 , hex = 0x64 , dec = 100 ) dans SPS NAL est le champ profile_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 pour un segment B bidirectionnel).

image

Si nous nous familiarisons avec la spécification du flux binaire H.264 pour SPS NAL, nous trouverons de nombreuses valeurs pour le nom, la catégorie et la description du paramètre. Par exemple, regardons les champs pic_width_in_mbs_minus_1 et pic_height_in_map_units_minus_1 .
Nom du paramètreCatégorieLa description
pic_width_in_mbs_minus_10ue (v)
pic_height_in_map_units_minus_10ue (v)
Si nous effectuons des opérations mathématiques avec les valeurs de ces champs, nous obtenons la permission. Vous pouvez imaginer 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 économiser de l'espace, au lieu de coder 1920, ils l'ont fait avec 119.

Si nous continuons à vérifier notre vidéo créée sous forme binaire (par exemple: xxd -b -c 11 v / minimal_yuv420.h264 ), alors nous pouvons passer au dernier NAL, qui est l'image elle-même.

image

Ici, nous voyons ses 6 premières valeurs d'octets: 01100101 10001000 10000100 00000000 00100001 11111111 . Comme il est connu que le premier octet indique le type de NAL, dans ce cas ( 00101 ), il s'agit d'un fragment IDR (5), et il sera alors possible de l'étudier davantage:

image

En utilisant les informations de spécification, il sera possible de décoder le type de fragment ( slice_type ) et le numéro de trame ( frame_num ) parmi d'autres champs 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 le code exponentiel de Golomb . Cette méthode est très efficace pour coder des valeurs de variable, en particulier lorsqu'il existe de nombreuses valeurs par défaut.

Les valeurs slice_type et frame_num de cette vidéo sont 7 (I-fragment) et 0 (première image).

Le bitstream peut être considéré comme un protocole. Si vous souhaitez en savoir plus sur le flux binaire, vous devez vous référer à la spécification UIT H.264 . Voici une macro montrant où se trouvent les données d'image ( YUV sous forme compressée).

image

Vous pouvez explorer d'autres flux binaires, tels que VP9 , H.265 ( HEVC ), ou même notre nouveau meilleur flux binaire AV1 . Sont-ils tous pareils? Non, mais en avoir traité au moins un est beaucoup plus facile à 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 regarder le code source qui analyse le flux binaire H.264 ( AVC ).

image

Pour vous entraîner, vous pouvez utiliser Intel Video Pro Analyzer (j'ai déjà dit que le programme est payant, mais existe-t-il une version d'essai gratuite avec une limite de 10 images?).

image

Revue


Notez que de nombreux codecs modernes utilisent le même modèle qu'ils viennent d'apprendre. Ici, jetons un coup d'œil au diagramme du codec vidéo Thor . Il contient toutes les mesures que nous avons prises. L'intérêt de cet article est pour vous de mieux comprendre les innovations et la documentation dans ce domaine.

image

Auparavant, il était estimé que 139 Go d'espace disque seraient nécessaires pour stocker un fichier vidéo d'une heure avec une qualité de 720p et 30 ips. Si vous utilisez les méthodes qui ont été discutées dans cet article (prévisions inter-trames et internes, conversion, quantification, codage entropique, etc.), alors vous pouvez réaliser (en supposant que nous dépensons 0,031 bits par pixel), la vidéo est de qualité assez satisfaisante, ce qui prend seulement 367,82 Mo, pas 139 Go de mémoire.

Comment le H.265 atteint-il un meilleur taux de compression que le H.264?


Maintenant que vous en savez plus sur le fonctionnement des codecs, il est plus facile de comprendre comment les nouveaux codecs peuvent fournir une résolution plus élevée avec moins de bits.

Lorsque vous comparez AVC et HEVC , vous ne devez pas oublier que c'est presque toujours un choix entre une charge CPU et un taux de compression plus élevés.

HEVC a plus d'options pour les sections (et sous-sections) que AVC , plus de directions pour les prévisions internes, un codage entropique amélioré, et bien plus encore. Toutes ces améliorations ont rendu H.265 capable de compresser 50% de plus que H.264 .

image



Partie I: notions de base sur la vidéo et l'image






Lisez aussi le blog
Société EDISON:


20 bibliothèques pour
application iOS spectaculaire

Source: https://habr.com/ru/post/fr480430/


All Articles