Pierwsza część:
Co? Kodek wideo to część oprogramowania/sprzętu, która kompresuje i/lub dekompresuje cyfrowe wideo.
Do czego? Niezależnie od pewnych ograniczeń związanych z przepustowością oraz
ilością miejsca na dane, rynek wymaga coraz wyższej jakości wideo. Pamiętacie, jak w poprzednim poście obliczyliśmy niezbędne minimum dla 30 klatek na sekundę, 24 bity na piksel, przy rozdzielczości 480×240? Otrzymaliśmy 82,944 Mbit/s bez kompresji. Kompresja to obecnie jedyny sposób na przesyłanie wideo HD/FullHD/4K na ekrany telewizyjne i do Internetu. Jak to jest osiągane? Teraz krótko omówimy główne metody.
Tłumaczenie wykonane przy wsparciu firmy EDISON Software.Zajmujemy się , a także .
Kodek vs Kontener
Powszechnym błędem nowicjuszy jest mylenie kodeka wideo z kontenerem wideo. Kontener to pewien format. Osłona, która zawiera metadane wideo (i być może audio). Skondensowane wideo można traktować jako ładunek kontenera.
Zwykle rozszerzenie pliku wideo wskazuje na jego rodzaj kontenera. Na przykład plik video.mp4 najprawdopodobniej jest kontenerem MPEG-4 Część 14, a plik o nazwie video.mkv to najprawdopodobniej . Aby być całkowicie pewnym kodeka i formatu kontenera, można skorzystać z lub .
Historia
Zanim przejdziemy do Jak?, zanurzmy się nieco w historię, aby lepiej zrozumieć niektóre stare kodeki.
Kodek wideo H.261 pojawił się w 1990 roku (technicznie — w 1988) i został stworzony do pracy przy prędkości transmisji 64 Kbit/s. Już w nim wykorzystano takie pomysły, jak subpróbkowanie koloru, makrobloki itp. W 1995 roku opublikowano standard kodeka wideo H.263, który rozwijano do 2001 roku.
W 2003 roku zakończono pierwszą wersję H.264/AVC. W tym samym roku firma „TrueMotion” wydała swój darmowy kodek wideo, kompresujący wideo z utratą, nazwany VP3. W 2008 roku Google kupił tę firmę, wydając VP8 w tym samym roku. W grudniu 2012 roku Google wydał VP9, i jest on wspierany przez około ¾ rynku przeglądarek (w tym urządzenia mobilne).
AV1 — to nowy darmowy kodek wideo z otwartym źródłem, opracowany przez Sojusz na rzecz otwartych mediów (AOMedia), w skład którego wchodzą znane firmy, takie jak: Google, Mozilla, Microsoft, Amazon, Netflix, AMD, ARM, NVidia, Intel i Cisco. Pierwsza wersja kodeka 0.1.0 została opublikowana 7 kwietnia 2016 roku.
Narodziny AV1
Na początku 2015 roku Google pracował nad VP10, Xiph (który należy do Mozilli) pracował nad Daala, a Cisco stworzyło swój darmowy kodek wideo o nazwie Thor.
Następnie MPEG LA najpierw ogłosiło roczne limity dla HEVC (H.265) i opłatę, 8 razy wyższą niż za H.264, ale wkrótce zmienili zasady:
bez rocznego limitu,
opłata za treść (0,5% przychodu) i
opłata za jednostkę produktu około 10 razy wyższa niż za H.264.
Sojusz ds. otwartych mediów został utworzony przez firmy z różnych branż: producentów sprzętu (Intel, AMD, ARM, Nvidia, Cisco), dostawców treści (Google, Netflix, Amazon), twórców przeglądarek (Google, Mozilla) i innych.
Firmy miały wspólny cel — kodek wideo bez opłat licencyjnych. Następnie pojawia się AV1 z dużo prostszą licencją patentową. Timothy B. Terriberry zaprezentował oszałamiającą prezentację, która stała się źródłem obecnej koncepcji AV1 i jej modelu licencjonowania.
Będziecie zaskoczeni, dowiadując się, że można analizować kodek AV1 przez przeglądarkę (zaciekawieni mogą przejść pod adres).

Uniwersalny kodek
Przyjrzymy się głównym mechanizmom, które leżą u podstaw uniwersalnego kodeka wideo. Większość z tych koncepcji jest przydatna i używana w nowoczesnych kodekach, takich jak VP9, AV1 i HEVC. Ostrzegam, że wiele rzeczy zostanie uproszczonych. Czasami będą używane prawdziwe przykłady (jak w przypadku H.264), aby zaprezentować technologie.
Krok 1 — podział obrazu
Pierwszym krokiem jest podział klatki na kilka sekcji, podsekcji i dalej.

Dlaczego? Jest wiele powodów. Kiedy dzielimy obraz, można dokładniej przewidywać wektor ruchu, używając małych sekcji dla małych poruszających się części. Natomiast dla statycznego tła można ograniczyć się do większych sekcji.
Zazwyczaj kodeki organizują te sekcje w sekcje (lub fragmenty), makrobloki (lub bloki drzewa kodowania) i szereg podsekcji. Maksymalny rozmiar tych sekcji jest zróżnicowany; HEVC ustala 64×64, podczas gdy AVC używa 16×16, a podsekcje mogą być dzielone do rozmiarów 4×4.
Pamiętacie rodzaje klatek z poprzedniego artykułu?! Można je zastosować również do bloków, tak więc mamy I-fragment, B-blok, P-makroblok itd.
Dla chętnych do praktyki — sprawdźcie, jak obraz zostanie podzielony na sekcje i podsekcje. Można do tego wykorzystać już wspomniane w poprzednim artykule. (ten płatny, ale z darmową wersją próbną, mającą ograniczenie na pierwsze 10 klatek). Tutaj zanalizowano sekcje. VP9:

2. krok — prognozowanie
Gdy tylko mamy sekcje, możemy tworzyć prognozy astrologiczne na ich podstawie. Dla PROGNOZOWANIA INTER- należy przekazać wektory ruchu i resztę, a do prognozowania INTRA przekazuje się kierunek prognozy i resztę.
3. krok — transformacja
Po uzyskaniu bloku resztkowego (przewidziana sekcja → rzeczywista sekcja), możliwe jest jej przekształcenie w sposób, aby wiedzieć, które piksele można odrzucić, zachowując przy tym ogólną jakość. Istnieją pewne transformacje zapewniające dokładne zachowanie.
Chociaż są też inne metody, zwróćmy uwagę na dyskretne przekształcenie cosinusowe (DCT — od discrete cosine transform). Główne funkcje DCT:
- Przekształca bloki pikseli w jednakowe bloki współczynników częstotliwości.
- Kompresuje moc, pomagając eliminować nadmiar przestrzenny.
- Zapewnia odwracalność.
2 lutego 2017 roku R.J. Cintra oraz F.M. Bayer opublikowali artykuł na temat DCT-podobnej transformacji do kompresji obrazów, wymagającej jedynie 14 dodatków.
Nie martwcie się, jeśli nie zrozumieliście zalet każdego punktu. Teraz na konkretnych przykładach upewnimy się o ich rzeczywistej wartości.
Weźmy taki blok pikseli 8×8:

Ten blok renderyzuje się w następujący obraz 8 na 8 pikseli:

Zastosujemy DCT do tego bloku pikseli i otrzymujemy blok współczynników o wymiarach 8×8:

A jeśli renderyzujemy ten blok współczynników, otrzymamy taki obraz:

Jak widzimy, nie przypomina on oryginalnego obrazu. Można zauważyć, że pierwszy współczynnik znacznie różni się od pozostałych. Ten pierwszy współczynnik znany jest jako współczynnik DC, reprezentujący wszystkie próbki w wejściowej tablicy, coś na wzór średniej.
Ten blok współczynników ma interesującą cechę: oddziela komponenty wysokoczęstotliwościowe od niskoczęstotliwościowych.

W obrazie większość mocy koncentruje się na niższych częstotliwościach, więc jeśli przekształcimy obraz w jego komponenty częstotliwościowe i odrzucimy wyższe współczynniki, możemy zmniejszyć ilość danych potrzebnych do opisania obrazu, nie poświęcając zbytnio jakości obrazu.
Częstotliwość oznacza, jak szybko zmienia się sygnał.
Spróbujmy zastosować wiedzę zdobytą w przykładzie testowym, przekształcając oryginalny obraz w jego częstotliwość (blok współczynników) za pomocą DCT, a następnie odrzucając część mniej ważnych współczynników.
Najpierw przekształcamy go w dziedzinę częstotliwości.

Następnie odrzucamy część (67%) współczynników, głównie w dolnej prawej części.

W końcu odbudowujemy obraz z tego odrzuconego bloku współczynników (pamiętaj, że musi być odwracalny) i porównujemy z oryginałem.

Widocznie przypomina oryginalny obraz, ale są liczne różnice w porównaniu z oryginałem. Odrzuciliśmy 67,1875% i nadal otrzymaliśmy coś przypominającego pierwowzór. Można było bardziej przemyślanie odrzucić współczynniki, aby uzyskać obraz o jeszcze lepszej jakości, ale to już temat na inną dyskusję.
Każdy współczynnik formowany jest za pomocą wszystkich pikseli.
Ważne: każdy współczynnik nie jest bezpośrednio przypisany do jednego piksela, lecz stanowi ważoną sumę wszystkich pikseli. Ten niezwykły wykres pokazuje, jak obliczany jest pierwszy i drugi współczynnik, używając wag unikalnych dla każdego indeksu.
Możesz również spróbować zwizualizować DCT, spoglądając na proste formowanie obrazu na jego podstawie. Na przykład, oto symbol A, formowany z użyciem każdego współczynnika wagowego:
Krok 4 — kwantyzacja.
Po odrzuceniu niektórych współczynników w poprzednim etapie, na ostatnim etapie (przekształcenie) przeprowadzamy szczególny rodzaj kwantyzacji. Na tym etapie utrata informacji jest dopuszczalna. Mówiąc prościej, będziemy kwantyzować współczynniki, aby osiągnąć kompresję.
Jak można kwantować blok współczynników? Jedną z najprostszych metod będzie jednolite kwantowanie, kiedy bierzemy blok, dzielimy go przez jedną wartość (przez 10) i zaokrąglamy to, co wyszło.

Czy możemy odwrócić ten blok współczynników? Tak, możemy, mnożąc przez tę samą wartość, przez którą dzieliliśmy.

Podejście to nie jest najlepsze, ponieważ nie uwzględnia ważności każdego współczynnika. Można byłoby zastosować macierz kwantyfikatorów zamiast jednej wartości, a ta macierz może wykorzystywać właściwości DCT, kwantując większość dolnych prawych i mniejszość górnych lewych.
5 krok — kodowanie entropowe
Po tym, jak zakwantowaliśmy dane (bloki obrazów, fragmenty, klatki), nadal możemy je kompresować bez utraty jakości. Istnieje wiele algorytmicznych metod kompresji danych. Krótko zaprezentujemy niektóre z nich, a w celu głębszego zrozumienia można przeczytać książkę „Zrozumienie kompresji: kompresja danych dla nowoczesnych deweloperów” (»).
Kodowanie wideo za pomocą VLC
Załóżmy, że mamy strumień symboli: a, e, r i t. Prawdopodobieństwo (w granicach od 0 do 1) tego, jak często każdy symbol występuje w strumieniu, przedstawione jest w tej tabeli.
| a | e | r | t | |
|---|---|---|---|---|
| Prawdopodobieństwo | 0,3 | 0,3 | 0,2 | 0,2 |
Możemy przypisać unikalne kody binarne (najlepiej małe) najbardziej prawdopodobnym, a większe kody — mniej prawdopodobnym.
| a | e | r | t | |
|---|---|---|---|---|
| Prawdopodobieństwo | 0,3 | 0,3 | 0,2 | 0,2 |
| Kod binarny | 0 | 10 | 110 | 1110 |
Kompresujemy strumień, zakładając, że w końcu wydamy 8 bitów na każdy symbol. Bez kompresji jeden symbol wymagałby 24 bitów. Jeśli każdy symbol zastąpić jego kodem, to wychodzi oszczędność!
Pierwszy krok to kodowanie symbolu e, który wynosi 10, a drugi symbol to a, który jest dodawany (niedokładnie matematycznie): [10] [0], a na końcu trzeci symbol t, który sprawia, że nasz finalny skompresowany strumień bitowy wynosi [10] [0] [1110] lub też 1001110, do czego potrzeba tylko 7 bitów (4 razy mniej miejsca niż w oryginale).
Zauważ, że każdy kod musi być unikalnym kodem prefiksowym. pomoże znaleźć te liczby. Chociaż metoda ta ma swoje niedoskonałości, istnieją kodeki wideo, które wciąż oferują tę algorytmiczną metodę kompresji.
Zarówno kodujący, jak i dekodujący muszą mieć dostęp do tabeli znaków z ich binarnymi kodami. Dlatego konieczne jest również przesłanie tabeli w danych wejściowych.
Kodowanie arytmetyczne
Załóżmy, że mamy strumień symboli: a, e, r, s i t, a ich prawdopodobieństwo jest przedstawione w tej tabeli.
| a | e | r | s | t | |
|---|---|---|---|---|---|
| Prawdopodobieństwo | 0,3 | 0,3 | 0,15 | 0,05 | 0,2 |
Z tą tabelą zbudujemy zakresy obejmujące wszystkie możliwe znaki, posortowane według największej ilości.

Teraz zakodujmy strumień składający się z trzech znaków: eat.
Najpierw wybieramy pierwszy znak e, który znajduje się w podzakresie od 0,3 do 0,6 (nie wliczając). Bierzemy ten podzakres i dzielimy go ponownie w tych samych proporcjach, co wcześniej, ale już dla tego nowego zakresu.

Kontynuujmy kodowanie naszego strumienia eat. Teraz bierzemy drugi znak a, który znajduje się w nowym podzakresie od 0,3 do 0,39, a następnie bierzemy nasz ostatni znak t i, powtarzając ten sam proces ponownie, otrzymujemy ostatni podzakres od 0,354 do 0,372.

Musimy po prostu wybrać liczbę w ostatnim podzakresie od 0,354 do 0,372. Wybierzmy 0,36 (można jednak wybrać dowolną inną liczbę w tym podzakresie). Tylko z tą liczbą będziemy mogli odtworzyć nasz oryginalny strumień. To jakbyśmy rysowali linię w granicach zakresów dla kodowania naszego strumienia.

Operacja odwrotna (czyli dekodowanie) jest równie prosta: mając naszą liczbę 0,36 i nasz początkowy zakres, możemy uruchomić ten sam proces. Ale teraz, używając tej liczby, ujawniamy strumień, zakodowany za pomocą tej liczby.
Z pierwszym zakresem zauważamy, że nasza liczba odpowiada przekrojowi, w związku z czym to nasz pierwszy znak. Teraz ponownie dzielimy ten podzakres, wykonując ten sam proces, co wcześniej. Tutaj można zauważyć, że 0,36 odpowiada znakowi a, a po powtórzeniu procesu dotarliśmy do ostatniego znaku t (tworząc nasz oryginalny zakodowany strumień eat).
I dla kodera, i dla dekodera powinna być dostępna tabela prawdopodobieństw znaków, dlatego konieczne jest przesłanie jej także w danych wejściowych.
Dość eleganckie, prawda? Ktoś, kto wymyślił to rozwiązanie, był naprawdę sprytny. Niektóre kodeki wideo wykorzystują tę technikę (lub, w każdym razie, oferują ją jako opcję).
Pomysł polega na bezstratnym kompresowaniu kwantowanego strumienia bitowego. W tym artykule na pewno brakuje wielu szczegółów, przyczyn, kompromisów itd. Ale jeśli jesteś programistą, powinieneś wiedzieć więcej. Nowe kodeki próbują wykorzystać różne algorytmy kodowania entropijnego, takie jak ANS.
Krok 6 — format strumienia bitowego
Po wykonaniu wszystkich tych kroków, pozostaje rozpakować skompresowane klatki w kontekście wykonanych działań. Należy wyraźnie poinformować dekoder o decyzjach podjętych przez kodera. Dekoder musi otrzymać wszystkie niezbędne informacje: głębokość bitowa, przestrzeń kolorów, rozdzielczość, informacje o prognozach (wektory ruchu, kierunkowe prognozowanie INTER), profil, poziom, liczba klatek, typ klatki, numer klatki i wiele więcej.
Pobierzemy powierzchownie strumień bitowy H.264. Naszym pierwszym krokiem jest stworzenie minimalnego strumienia bitowego H.264 (FFmpeg domyślnie dodaje wszystkie parametry kodowania, takie jak SEI NAL — wkrótce dowiemy się, czym to jest). Możemy to zrobić, używając naszej własnej repozytorium i FFmpeg.
. /s/ffmpeg -i /files/i/minimal.png -pix_fmt yuv420p /files/v/minimal_yuv420.h264
Podana komenda wygeneruje surowy strumień bitowy H.264 z jedną klatką, rozdzielczością 64×64, z przestrzenią kolorów YUV420. Jako klatkę wykorzystamy następujący obraz.

Strumień bitowy H.264
Standard AVC (H.264) określa, że informacja będzie przesyłana w makrokdatach (w rozumieniu sieci), zwanych NAL (to jest pewien poziom abstrakcji sieci). Głównym celem NAL jest dostarczenie „przyjaznego dla sieci” przedstawienia wideo. Ten standard powinien działać na telewizorach (w oparciu o strumienie), w Internecie (w oparciu o pakiety).
![]()
Istnieje znacznik synchronizacji do określania granic elementów NAL. Każdy znacznik synchronizacji zawiera wartość 0x00 0x00 0x01, z wyjątkiem pierwszego, który wynosi 0x00 0x00 0x00 0x01. Jeśli uruchomimy hexdump dla wygenerowanego strumienia bitowego H.264, zidentyfikujemy co najmniej trzy wzorce NAL na początku pliku.

Jak wspomniano, dekoder musi znać nie tylko dane obrazu, ale także szczegóły wideo, klatki, kolory, używane parametry i wiele więcej. Pierwszy bajt każdego NAL określa jego kategorię i typ.
| Identyfikator typu NAL | Opis |
|---|---|
| 0 | Nieznany typ |
| 1 | Zakodowany fragment obrazu bez IDR |
| 2 | Kodowany segment danych wycinka A |
| 3 | Kodowany segment danych wycinka B |
| 4 | Kodowany segment danych wycinka C |
| 5 | Kodowany fragment IDR obrazu |
| 6 | Dodatkowe informacje o rozszerzeniu SEI |
| 7 | Zbiór parametrów sekwencji SPS |
| 8 | Zbiór parametrów PPS obrazu |
| 9 | Separator dostępu |
| 10 | Koniec sekwencji |
| 11 | Koniec strumienia |
| … | … |
Zazwyczaj pierwszy NAL w strumieniu bitowym to SPS. Ten typ NAL odpowiada za informowanie o ogólnych zmiennych kodowania, takich jak profil, poziom, rozdzielczość i inne.
Jeśli pominiesz pierwszy znacznik synchronizacji, możemy zdekompresować pierwszy bajt, aby dowiedzieć się, jaki typ NAL jest pierwszy.
Na przykład, pierwszy bajt po znaczniku synchronizacji wynosi 01100111, gdzie pierwszy bit (0) znajduje się w polu forbidden_zero_bit. Następne 2 bity (11) informują nas o polu nal_ref_idc, które wskazuje, czy ten NAL jest polem odwołania, czy nie. A pozostałe 5 bitów (00111) informują nas o polu nal_unit_type, w tym przypadku to blok SPS (7) NAL.
Drugi bajt (binarny=01100100, szesnastkowy=0x64, dziesiętny=100) w SPS NAL to pole profile_idc, które pokazuje profil, który wykorzystał encoder. W tym przypadku użyto ograniczonego profilu wysokiego (tj. wysokiego profilu bez wsparcia dla dwukierunkowego segmentu B).

Jeśli zapoznamy się ze specyfikacją strumienia bitowego H.264 dla SPS NAL, odkryjemy wiele wartości dla nazwy parametru, kategorii i opisu. Na przykład, przyjrzyjmy się polom pic_width_in_mbs_minus_1 i pic_height_in_map_units_minus_1.
| Nazwa parametru | Kategoria | Opis |
|---|---|---|
| pic_width_in_mbs_minus_1 | 0 | ue(v) |
| pic_height_in_map_units_minus_1 | 0 | ue(v) |
Jeśli wykonasz kilka operacji matematycznych na wartościach tych pól, uzyskasz rozdzielczość. Można przedstawić 1920 x 1080, używając pic_width_in_mbs_minus_1 o wartości 119 ((119 + 1) * macroblock_size = 120 * 16 = 1920). Ponownie, oszczędzając miejsce, zamiast kodować 1920 zrobiono to z 119.
Jeśli kontynuujesz sprawdzanie naszego stworzonego wideo w formie binarnej (na przykład: xxd -b -c 11 v/minimal_yuv420.h264), możesz przejść do ostatniego NAL, którym jest sam kadru.

Tu widzimy jego pierwsze 6 bajtowych wartości: 01100101 10001000 10000100 00000000 00100001 11111111. Ponieważ wiadomo, że pierwszy bajt wskazuje na typ NAL, w tym przypadku (00101) to fragment IDR (5), a następnie dodatkowo może zbadać jego:

Używając informacji ze specyfikacji, można zdekodować typ fragmentu (slice_type) i numer klatki (frame_num) wśród innych istotnych pól.
Aby uzyskać wartości niektórych pól (ue(v), me(v), se(v) lub te(v), musimy zdekodować fragment, korzystając z specjalnego dekodera opartego na Ta metoda jest bardzo skuteczna w kodowaniu wartości zmiennych, zwłaszcza gdy istnieje wiele wartości domyślnych.
Wartości slice_type i frame_num tego wideo są równe 7 (fragment I) i 0 (pierwsza klatka).
Strumień bitowy można traktować jako protokół. Jeśli chcesz dowiedzieć się więcej o strumieniu bitowym, warto skonsultować się z dokumentacją ITU H.264. Oto makroschemat ilustrujący, gdzie znajdują się dane obrazu (YUV w skompresowanej formie).

Można badać również inne strumienie bitowe, takie jak VP9, H.265 (HEVC) lub nawet nasz nowy najlepszy strumień bitowy AV1. Czy są one podobne? Nie, ale zrozumienie chociaż jednego z nich znacznie ułatwia zrozumienie pozostałych.
Chcesz poćwiczyć? Zbadaj strumień bitów H.264
Można wygenerować jednoklatkowe wideo i wykorzystać MediaInfo do analizy strumienia bitów H.264. W rzeczywistości nic nie stoi na przeszkodzie, aby spojrzeć na kod źródłowy, który analizuje strumień bitów. H.264 (AVC).
Do ćwiczeń można użyć Intel Video Pro Analyzer (już chyba mówiłem, że program jest płatny, ale dostępna jest bezpłatna wersja próbna z limitem 10 klatek?).
Przegląd
Należy zauważyć, że wiele nowoczesnych kodeków korzysta z tego samego modelu, który właśnie omówiliśmy. Oto spójrzmy na diagram kodeka wideo Thor. Zawiera wszystkie kroki, które przeszliśmy. Cały sens tej notatki polega na tym, aby przynajmniej lepiej zrozumieć innowacje i dokumentację w tej dziedzinie.

Wcześniej obliczono, że potrzebne będzie 139 GB miejsca na dysku do przechowania pliku wideo trwającego jedną godzinę przy jakości 720p i 30 fps. Jeśli zastosujemy metody omówione w tym artykule (prognozy międzyklatkowe i wewnętrzne, transformacje, kwantyzacja, kodowanie entropijne itp.), możemy osiągnąć (zakładając, że wydajemy 0,031 bitu na piksel) wideo o całkiem satysfakcjonującej jakości, które zajmuje tylko 367,82 MB, a nie 139 GB pamięci.
Jak H.265 osiąga lepszy stopień kompresji niż H.264?
Teraz, gdy wiadomo więcej o tym, jak działają kodeki, łatwiej jest zrozumieć, jak nowe kodeki mogą zapewniać wyższe rozdzielczości przy mniejszej ilości bitów.
Porównując AVC i HEVC, należy pamiętać, że prawie zawsze jest to wybór między większym obciążeniem CPU a stopniem kompresji.
HEVC ma więcej opcji sekcji (i podsekcji) niż AVC, więcej kierunków wewnętrznego prognozowania, ulepszone kodowanie entropii i wiele więcej. Wszystkie te ulepszenia sprawiły, że H.265 jest w stanie kompresować o 50% więcej niż H.264.

Pierwsza część:
Źródło: habr.com




