• Share this text:
Report Abuse
Untitled - posted by guest on 23rd September 2020 10:26:06 PM

[🇨🇳](/README-cn.md "Simplified Chinese")

[🇯🇵](/README-ja.md "Japanese")

[🇮🇹](/README-it.md "Italian")

[🇰🇷](/README-ko.md "Korean")


[![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)


# Интро

Нежное интро к видео технологии, предназначено для программистов и инженеров, хотя информация тут изучаема **любому** заинтересованному. Эта идея родилась во время [мини-семинара для новичков в области видео технологий](https://docs.google.com/presentation/d/17Z31kEkl_NGJ0M66reqr9_uTG6tI5EDDVXpdPKVuIrs/edit#slide=id.p).


Цель представить концепции цифрового видео **простыми терминами, схемами и практикой**. Не стесняйтесь добавлять свои исправления и предложения для улучшения документа.


**Практические разделы** требуют чтобы у вас был установлен **docker** и клонирован этот репо.


```bash

git clone https://github.com/leandromoreira/digital_video_introduction.git

cd digital_video_introduction

./setup.sh

```


> **ПРЕДУПРЕЖДЕНИЕ**: когда вы видите команду `./s/ffmpeg` или `./s/mediainfo`, это означает, что мы запускаем **контейнерную версию** этой программы, которая уже включает в себя все необходимые требования.


Все **практические упражнения выполняются из клонированной папки**. Для **примеров jupyter** вы должны запустить сервер `./s/start_jupyter.sh`, и посетить URL в браузере.


# Changelog


* added DRM system

* released version 1.0.0

* added simplified Chinese translation


# Индекс


- [Интро](#интро)

- [Индекс](#индекс)

- [Основные термины](#основные-термины)

  * [Другие способы кодирования цветного изображения](#другие-способы-кодирование-изображений)

  * [Практика: експерементируем цветами и изображениями](#практика-експерементируем-цветами-и-изображениями)

  * [DVD это DAR 4:3](#dvd-это-dar-43)

  * [Практика: Рассмотр свойсвтва видео](#практика-рассмотр-свойства-видео)

- [Удаление избыточности](#удаление-избыточности)

  * [Цвета, яркость и глаза](#цвета-яркость-и-глаза")

    + [Модель цвета](#модель-цвета)

    + [Преобразование между YCbCr и RGB](#преобразование-между-ycbcr-и-rgb)

    + [Цветовая субдискретизация](#цветовая-субдискретизация)

    + [Практика: Проверка гистограммы YCbCr](#практика-проверка-гистограммы-ycbcr)

  * [Типы кадров](#типы-кадров)

    + [I кадр (интра, ключевой кадр)](#i-кадр-интра-ключевой-кадр)

    + [P кадр (предсказанный)](#p-кадр-предсказанный)

      - [Практика: Видео с единым I-кадром](#практика-видео-с-единым-i-кадром)

    + [B кадр (двунаправленного предсказания)](#b-кадр-двунаправленного-предсказания)

      - [Практика: Сравнивание видео с Б-кадрами](#практика-сравнивание-видео-с-б-кадрами)

    + [Конспект](#конспект)

  * [Временная избыточность (меж предскозание)](#временная-избыточность-меж-предскозание)

      - [Практика: Обзор векторов движения](#практика-обзор-векторов-движения)

  * [Пространственная избыточность (внутреннее предсказание)](#пространственная-избыточность-внутреннее-предсказание)

      - [Практика: проверка внутренних предсказаний](#практика-проверка-внутренних-предсказаний)

- [Как работает видеокодек?](#как-работает-видеокодек)

  * [Что? Почему? Как?](#что-почему-как)

  * [История](#история)

    + [Рождение AV1](#рождение-av1)

  * [Универсальный кодек](#универсальный-кодек)

  * [1-й шаг - разделение изображений](#1-й-шаг---разделение-изображений)

    + [Практика: Проверка разделов](#практика-проверка-разделов)

  * [2-й шаг - предсказания](#2-й-шаг---предсказания)

  * [3-й шаг - трансформация](#3-й-шаг---трансформация)

    + [Практика: выбрасывание разных коэффициентов](#практика-выбрасывание-разных-коэффициентов)

  * [4-й шаг - квантование](#4-й-шаг---квантование)

    + [Практика: квантование](#практика-квантование)

  * [5-й шаг - энтропийное кодирование](#5-й-шаг---энтропийное-кодирование)

    + [VLC-кодирование](#vlc-кодирование)

    + [Арифметическое кодирование](#арифметическое-кодирование)

    + [Практика: CABAC vs CAVLC](#практика-cabac-vs-cavlc)

  * [6-й шаг - формат битового потока](#6-й-шаг---формат-битового-потока)

    + [H.264 битовый поток](#h264-битовый-поток)

    + [Практика: Проверка битовога потока H.264](#практика-проверйа-битовога-потока-h264)

  * [Обзор](#oбзор)

  * [Как H.265 обеспечивает лучшую степень сжатия чем H.264?](#как-h265-обеспечивает-лучшую-степень-сжатия-чем-h264)

- [Онлайн трансляция](#онлайн-трансляция)

  * [Общая архитектура](#общая-архитектура)

  * [Прогрессивная загрузка и адаптивная передача](#прогрессивная-загрузка-и-адаптивная-передача)

  * [Защита контента](#защита-контента)

- [Как использовать jupyter](#как-использовать-jupyter)

- [Конференции](#конференции)

- [Ссылки](#ссылки)


# Основные термины


**Изображение** можно предстовлять в форме **2Д матрицы**. Если мы думаем о **цветах**, то можно екстропалировать это представлиние в **3Д матрицу**, где **добавочные измерения** показывают **цветную информацию**.


Если мы представляем ети цвета [первичными цветами (красный, зеленый, синий](https://en.wikipedia.org/wiki/Primary_color), мы определяем три уровня, один для **красного**, один для **зеленого**, и последний для **синего**.


![изображение это 3Д матрица](/i/image_3d_matrix_rgb.png "Изображение это 3Д матрица")


Мы назовем каждую точку на етой матрицы **пикселем** (елемент изображения). Один пиксел отражает **интенсивность** (обычно числовое значение) данного цвета. Например, **красний пиксель** имеет 0 зеленого, 0 синего, и максимально красного. **Розовый пиксель** состоит из комбинации трех цветов - **Красный=255, Зеленый=192, Синиий=203**.


> #### Другие способы кодирование изображений

> Существует множество моделий которые описовают как расппределяються цвета на изображение. Например, в место трех битов, как для модели RGB (Красный, Зеленый, Синий) мы можем изпользовать только один бит. Ето использует меньше памяати но так же дает меньшые количество цветов.


>

> ![сбор цветов приставки NES](/i/nes-color-palette.png "сбор цветов приставки NES")


На изображение снизу, первый снимок отражает все цветовые каналы. Остальные снимки только отражаяют красный, зеленый и синий канал.


![Интенсивность RGB каналов](/i/rgb_channels_intensity.png "Интенсивность RGB каналовintensity")


Мы видем что **красний канал** будет самым ярким (белые части второго лица), и способствует главному оттенку в картинке. **Синего** мало, и видно в четвертой картинке что он **сконцентрирован в глазах и одежды** Марио. Так же видно что все каналы мало способствуют усам, самым темным частям картинки.


У каждого канала опредиленное каличество битов, так называема **битовая глубина**. Если у нас **8 битов** (между 0 и 255и) для каждего цвета, то битовая глубина у изображений RGB (8 бит * 3 цвета) в размере **24 бита**, то есть 2^24 разных цвета.


> **Хорошо знать** [как озпбражения переводятся с настоящего мира в биты](http://www.cambridgeincolour.com/tutorials/camera-sensors.htm).


Другая чарактеристика изображений ето **разрешение**, то есть каличество пикселей в одном измерение. Обычно оно показываетсья в формате шырина х высота, как на **4х4** картинке снизу.


![Разрешение изображения](/i/resolution.png "Разрешение изображения")


> #### Практика: експерементируем цветами и изображениями

> Можно [играца с цветами в картинках](/image_as_3d_array.ipynb) используя [jupyter](#how-to-use-jupyter) (python, numpy, matplotlib и т.д).

>

> Так же можшно понять [как фильтры, (обострение, размытость...) работают](/filters_are_easy.ipynb).


Еще качество с которым мы встречаемся пре работе с видео и изображениями это **соотношение сторон (AR)** которое просто описовает пропорции ширины сранвнительно с высотой изображения или пикселя.


Когда луди говорят что изображение или филъм **16х9**, они называют цифры **DAR (Соотношение сторон дисплея)**. Так же и бывает **PAR (Соотношение сторон пикселя)**


![DAR](/i/DAR.png "DAR")


![PAR](/i/PAR.png "PAR")


> #### DVD это DAR 4:3

> Хоть у DVD разрешение 704х480, формат все равно соблюдает DAR 4:3 потому что у него PAR 10:11 (703x10/480x11)


И конечно, "видео" мы опредиляем как **последствие *n*-кадров** во **времини**, что можно обозначить как дополнительное измерение поверху размера и цвета, где *п* это колучество кадров в секунду (FPS).


![видео](/i/video.png "видео")


**битрейт** это сколько нужно битов что бы показать секунду видео.


> битрейт = ширина * высота * битовая глубина * кадры в секунду


Например, видео корое 30 FPS, 24 бита на пиксел, с разрешением 480х240 использует **82,944,000 битов в секунду** или 82 мегабита/с (30*480х240х24) без компрессии/снижения качества.


Когда **бит рейт** постоянный то его называют постоянным битрейтом (**CBR**), когда он меняетсья со времинем тогда это переменный битрейт (**VBR**).


> Этот график показывает ограниченный VBR, который не тратит слишком много битов на черные кадры.

>

> ![ограниченный VBR](/i/vbr.png "ограниченный VBR")


Раньше, енжинеры предумали технику што бы увеличить воспринятый FPS в два раза при этом не **не увеличевыя битрейт**. Эта техника называетсья **чересстрочное видео**, где пол изображения посылаетсья в одном "кадре" и другая половина в следущем "кадре".


На севоднешний день экраны обычно предстовляют видео техникой **прогресивного скана**. Это способ показывания, хранения и перевода изображений в котором все линии каждего кадра нарисованы одна за другой.


![чересстрочное видео против прогресивный скан](/i/interlaced_vs_progressive.png "чересстрочное видео против прогресивный скан")


Теперь у нас есть предиставление того как xраница **изображение** в цифровом формате, как его **цвета** разположены, сколько **битов в секунду** мы используем что бы показывать видео, если это постоянный битрейт (CBR) или переменный битрейт (VBR), и как это связано с **разрешением** при данной **чистоте кадра**. Так же мы более знакомы с терминами на подобие **чересстрочное видео**, PAR, и т.д. 


> #### Практика: Рассмотр свойсвтва видео

> Вам возможно [увидеть оговоринные свойства с помощью ffmpeg или mediainfo.](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#inspect-stream)


# Удаление избыточности


Быстро становитсья ячевидно что работать с видео без компресии практическии не возможно; **один час видео** при разрешение 720p, с частотой кадра 30fps занимает **278GB памяти<sup>*</sup>**. Алгоритмы компресии без потерь, на подобие DEFLATE (использовается в PKZIP, Gzip, PNG) **не сжимают видео достаточно** нам надо искать другие способы сжатья видео.


> <sup>*</sup> Эту цифру мы получаем умнажая 1280 х 720 х 24 х 30 х 3600 (ширина, высота, витовая глубина, чистота кадра и время в секундах).


Для этого мы можем експлойтеривоать **характеристики нашего зрения**. Мы разбераем яркость лучше чем цвета. Так же более заметные **повторы частей изобразения во времини**.


## Цвета, яркость и глаза


Наши глаза более чуствительны к [яркосте чем к цветам](http://vanseodesign.com/web-design/color-luminance/), проверти для себя на этом изображение:


![яркость против цвета](/i/luminance_vs_color.png "яркость против цвета")


Если вы не видети что цвета **квадрата А и Б одинаковые** у картинке с лева, то у вас все в порядке, наш мозг настроин **уделять больше внимания на яркость/темноту чем на цвет**. С право вы видите што цвета и в правду одинаковы.


> **Упрощенное обьяснение функций глаз**

> Глаз [сложный орган](http://www.biologymad.com/nervoussystem/eyenotes.htm), составлин из многих частей, хотя нас интересует шишочные и палочные клетки. Глаз состоит из порядка [120 милион палочных клеток и 6 милион шишочныч клеток](https://en.wikipedia.org/wiki/Photoreceptor_cell).

>

> **Упращая дальше**, давайте посмотрим как цвет и яркость действуют на глаза. **[Палочные клетки](https://en.wikipedia.org/wiki/Rod_cell) по большенству отвецтвенны за восприятие яркости**. **[Шишичные клетки](https://en.wikipedia.org/wiki/Cone_cell) отвецтвенны за восприятие цвета**. Есты три типа шишки, каждая со своей окраской: [S-шишки (Синий), M-шишки (Зеленый) и L-cones (Красный)](https://upload.wikimedia.org/wikipedia/commons/1/1e/Cones_SMJ2_E.svg).

>

> Потому что у нас больше палочных клеток (яркость) чем шишочных (цвет), мы делаем вывод что мы обробатываем больше яркостной информации.

>

> ![состав глаз](/i/eyes.jpg "состав глаз")

>

> **Функции контрастной чувствительности**

> Есть много теорий описывая функции человеческое зрение. Одна из них называется "Функции контрастной чувствительности". Они описывают сколько изминения в цвете может произойти перед тем как наблюдающий его замечает. Функции измеряют не только чуствительность к черно белому, нo так же и яркость при цветах. Експерименты раз за разом показывают что мы более чуствительны к яркости чем к цветам.


Зная что мы чувствительны к яркосте, мы можем попытатся эксплойтировать этот факт.


### Модель цвета


В начале мы изучали как [распределять цвет на изображениях](#основные-термины) используя **модель RGB**. Существуют другие модели - например, **YCbCr**<sup>*</sup> делит luma/лума (яркость) от chrominance/хроминанц (цветность).


> <sup>*</sup> есть другие модели которые так же разделяют между яркостью и цветом.


В этой моделе **Y** канал яркости. Так же есть два канала цвета, **Cb** (синяя chroma/хрома) и **Cr** (красная chroma/хрома). Формат [YCbCr](https://en.wikipedia.org/wiki/YCbCr) возможно получить от RGB, и так же можно получить RGB от YCbCr. С помощью YCbCr мы можем состовлять изображения в полном цвете:


![пример ycbcr](/i/ycbcr.png "пример ycbcr")


### Преобразование между YCbCr и RGB


Некоторые из вас может спрашивают, как можно показывать **все цвета без зеленого**?


Что бы понятжь ответ, давайте посмотрим как мы переводим цветовую модель RGB на YCbCr. Мы будем использовать коэфиценты из стандарта **[BT.601](https://en.wikipedia.org/wiki/Rec._601)**, который был создан **[группой ITU-R<sup>*</sup>](https://en.wikipedia.org/wiki/ITU-R)**. Первый шаг в этом процессе это **высчитать яркость (luma)** и заменить цыфры RGB, используя константы ракомендованны группой ITU.


```

Y = 0.299R + 0.587G + 0.114B

```


После яркости, мы можем **получить цвета** цвета (chroma синий и красный):


```

Cb = 0.564(B - Y)

Cr = 0.713(R - Y)

```


Можно **перевести этот результат обратно**, и дажше **получить зеленый используя YCbCr**


```

R = Y + 1.402Cr

B = Y + 1.772Cb

G = Y - 0.344Cb - 0.714Cr

```


> <sup>*</sup> Цыфровым видео правят группы и стандарты. Группы определяют стандарты, на пример [что такое 4К? Какую чистоту кадра использоватъ? Решение? Цветную модель?](https://en.wikipedia.org/wiki/Rec._2020).


Обычно, **дисплеи** работают только в режиме модели **RGB**, разположеные каким то образом. Некоторые из них показанны тут:


![пиксельная геометрия](/i/new_pixel_geometry.jpg "пиксельная геометрия")


### Цветовая субдискретизация


Когда изображение представлено компонентами яркости и цвета, мы можшем воспользоватся чуствительностью глаза к яркосте что бы уменьшить количество информации. **Цветовая субдискретизация** техника кодированья изображении с **разрешением для цвета меньше чем для яркости**.


![субдискретизация ycbcr](/i/ycbcr_subsampling_resolution.png "субдискретизация ycbcr")


Так как же уменшаеться разрешение цвета?! Существуют схемы которые описовают как получать цвет от разных разрешений для одного изображение (`конечный цвет = Y + Cb + Cr`).


Эти схемы называются системами субдискретизации, обычно показаны соотношением трех чисел - `a:x:y` которое опредиляет разрешение цвета по отношению к `a * 2` блоку пикселей яркости.


 * `a` горизонтальная ширина (обычно 4)

 * `x` количество образцов цвета в первом ряду

 * `y` количество изменений цвета между первым и вторым рядом

 

> В этой схеме есть изклучение, 4:1:0, где выберается только один цвет для каждего `4 x 4` блока разрешения яркости. 


В современных кодеках обычно использыются форматы: **4:4:4** *(Без субдискритизации)*, **4:2:2, 4:1:1, 4:2:0, 4:1:0 и 3:1:1**.


> Вы можете участовать в [разговорах о цветовой подборке тут](https://github.com/leandromoreira/digital_video_introduction/issues?q=YCbCr).


> **Подборка YCbCr 4:2:0**

>

> Тут видно как сливается цветовая информация с яркостной в режшиме YCbCr 4:2:0. Заметите, что мы только используем 12 битов на пиксель.

>

> ![слитие YCbCr 4:2:0](/i/ycbcr_420_merge.png "слитие YCbCr 4:2:0 merge")


Тут показоно изображение кодированое главными типами субдискретизация. Первый ряд финальний YCbCr; на втором, видно разрешение цветных каналов. Качество изображения нормальное, при этом памяти используется на много меньше.


![примеры субдискретизация](/i/chroma_subsampling_examples.jpg "примеры субдискретизация")


Раньее мы вычеслили что нам надо [278GB памяти что бы сохранить час 720p/30fps видео](#удаление-избыточности). Используя режим **YCbCr 4:2:0** мы можем **убрать половину размера до 139GB**<sup>*</sup>, хотя это все равно далеко от идеала.


> <sup>*</sup> это число можно получить умнажая ширину, высоту, биты на пиксел, и чистоту кадра. Раньше мы пользовались 24 битами, теперь нам только надо 12.


<br/>


> ### Практика: Проверка гистограммы YCbCr

> Возможно проверить [гистограмму YCbCr с помошью ffmpeg.](/encoding_pratical_examples.md#generates-yuv-histogram). У этого изображение выше концентрация синего, что видно на [гистограмме](https://en.wikipedia.org/wiki/Histogram).

>

> ![гистограмма ycbcr](/i/yuv_histogram.png "гистограмма ycbcr")


### Цвет, лума, яркость, гамма


Отличное видео для тех кто хотят преобрезти глубже понятие лумы, яркости, гаммы, и цвета.

[![Analog Luma - A history and explanation of video](http://img.youtube.com/vi/Ymt47wXUDEU/0.jpg)](http://www.youtube.com/watch?v=Ymt47wXUDEU)


## Типы кадров


Теперь мы можем сосридоточится на удаление **избыточности во времини**. С начала, нам надо установить основные термины - скажим, что мы работаем с фильмом 30FPS, и первые 4 кадра выглядят так:


![шар 1](/i/smw_background_ball_1.png "шар 1") ![шар 2](/i/smw_background_ball_2.png "шар 2") ![шар 3](/i/smw_background_ball_3.png "шар 3")

![шар 4](/i/smw_background_ball_4.png "шар 4")


Мы видим много повторений между кадрами, например у синего фона который не мениается на кадрах 0 - 3. Что бы начать решать эту проблему, мы можем абстрактно классифицировать их как 3 разныч типа кадра.


### I кадр (интра, ключевой кадр)


I кадр, (ссылка, ключевой кадр, внутренний) **независемый кадр**. Что бы его нарисвоать не нужно дополнительной информации, и он похож на фотографию. Первый кадр обычно I кадр, но мы увидем как I кадры регулярно вставляют среди другич типов кадра. 


![шар 1](/i/smw_background_ball_1.png "шар 1")


### P кадр (предсказанный)


P-кадр пользуется фактом что почти всегда можно нарисовать изображение **с помощью преведущего кадра**. Например, во втором кадре, шар поменял расположение - все остольное осталось одинаковым. Мы можем построить **первый кадр используя только разницу между двумя кадрами**.


![шар 1](/i/smw_background_ball_1.png "шар 1") <- ![шар 2](/i/smw_background_ball_2_diff.png "шар 2")


> #### Практика: Видео с единым I-кадром


> Если P-кадры используют меньше памяти, то почему бы нам не закодировать целое [видео одним I-кадром и оставить все последующие кадры как P-кадры?](/encoding_pratical_examples.md#1-i-frame-and-the-rest-p-frames)

>

> После кодировки этого видео, начните смотреть его и попробуйте перескочить к пожемму времини. Станит заметно что эта функция длица **долгое време**. **P-кадрам нужны ссылочные кадры** (например I-кадр) что бы их нарисовать.

>

> Так же можно закодировать видео с одним I-кадром а потом попробовать [закодировать его вставляя I-кадр каждие две секунды](/encoding_pratical_examples.md#1-i-frames-per-second-vs-05-i-frames-per-second), сравнивая размера в конце.


### B кадр (двунаправленного предсказания)


Так же можно ссылаца на будущие кадры как и преведущие, метод который економит еще больше памяти - как раз это и делают B-кадры.


![шар 1](/i/smw_background_ball_1.png "шар 1") <- ![шар 2](/i/smw_background_ball_2_diff.png "шар 2") -> ![шар 3](/i/smw_background_ball_3.png "шар 3")


> #### Практика: Сравнивание видео с Б-кадрами

> Вы можете составить две версии видео, одну с B-кадрами и другую [вообще без B-кадров](/encoding_pratical_examples.md#no-b-frames-at-all). Обратите внемание на размер файла и качество видео.


### Конспект


Эти кадры используются для **более ефективной компресии**. Мы увидем как это произхoдит в следующем отделе, на не теперешний момент нам достаточно помнить что **I-кадр дорогой, P-кадр дешевле и B-кадр самый дешевый**.


![типы кадров](/i/frame_types.png "типы кадров")


## Временная избыточность (меж предскозание)


Давайте посмотрим как мы можем понизеть количество **повторов во времини**. Такого типа избыточности можно достич техниками **меж предсказания**.


По попробуем **потратить меньше битов** кодируя кадры 0 и 1.


![оригинальные кадры](/i/original_frames.png "оригинальные кадры")


Один подход это просто **вычитать разницу между кадром 1 и 0**, и мы получим все что надо что бы **закодировать остаток**.


![кадры делта](/i/difference_frames.png "кадры делта")


Не плохо, но есть еще **лучше метод**, который использует еще меньше битов. С начала, давай разрежим `кадр 0` на серию разделов, после чего мы можем попытатся соотвецтвовать разделы с `кадра 0` до `кадра 1`, действие наподобие **оценки девежения**.


> ### Википедиа - компенсация движению блока

> **Компенсаци движению блока** делит текущий кадр на отдлеьные разделы, после чего векторы компенсации движения **показывают от куда эти блоки появились** (распостраненная ошыбка идея того что, разделив преведущий кадр на отдельные разделы, векторы показывают куда эти разделы двигаются). Исходные разделы обычно перекрывают друг друга в исходном кадре. Некотороя компрессия видео текущий кадр из кусков разных ранее переданных кадров.


![делта кадры](/i/original_frames_motion_estimation.png "делта кадры")


Мы можем предсказать что шарик сдвинулся от `x=0, y=25` до `x=6, y=26`, и что **х** и **y** числа это **векторы движения**. Что бы сэкономить на битах дальше, мы можем **закодривоть только разницу в векторах двюижения** между последним положением блока и предсказанным, так что финальный вектор движения получается `x=6 (6-0), y=1 (26-25)`.


> При настоящем использование этой техники, шар был бы разделен на `n` разделов. Процесс при этом остается одинаковым.


> Обьекты на кадре **могут двигатся 3Dобразно**, шар может стать меньше когда он уходит в фон. Впольне возможно (и нормально) что мы не сможем найти идеальнoe совпадение для раздела которму мы ищим совпадение. Вот изображение сравняя наше предскозание с настоящим кадром.


![предсказание движения](/i/motion_estimation.png "предсказание движения")


Все равно, видно что когда мы используем **предсказание движения** информации которую нам **надо кодировать меньше** чем если мы бы использовали технику делта кадров.


![предсказание движения против делты](/i/comparison_delta_vs_motion_estimation.png "предсказание движения против делты")


> ### Как выглядет настоящая компенсация движения

> Обычно эта техника используется для всех разделов, и обычно один шар как в преведущих кадрах будет разделен на несколько разделов.

> ![настоящая компенсация движения](/i/real_world_motion_compensation.png "настоящая компенсация движения")

> Ссылка: https://web.stanford.edu/class/ee398a/handouts/lectures/EE398a_MotionEstimation_2012.pdf


Вы можете [експерементировать этими техниками в jupyter](/frame_difference_vs_motion_estimation_plus_residual.ipynb).


> #### Практика: Обзор векторов движения

> Мы можем [создать видео с внешним предсказанием (векторами движения) с помощью ffmpeg.](/encoding_pratical_examples.md#generate-debug-video)

>

> ![внешние предсказание (векторы движения) с помощью ffmpeg](/i/motion_vectors_ffmpeg.png "внешние предсказание (векторы движения) с помощью ffmpeg")

>

> Так же можно использовать [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (програма платная, но есть бесплатная, пробная версия, которая ограничивает пользу на первые 10 кадров).

>

> ![внешние предсказание intel video pro analyzer](/i/inter_prediction_intel_video_pro_analyzer.png "внешние предсказание intel video pro analyzer")


## Пространственная избыточность (внутреннее предсказание)


Если мы проанализируем **каждый кадр** в видео, мы увидим что есть **много областей, которые имеют отношение друг к другу**.


![](/i/repetitions_in_space.png)


Давайте пройдемся по примеру. Эта сцена в основном состоит из синего и белого.


![](/i/smw_bg.png)


Это `I-кадр`, и мы **не можем использовать предыдущие кадры** для прогнозирования - при этом, мы все еще можем сжать его. Мы закодируем информацию в красном разделе. Если мы **посмотрим на его соседей**, мы можем понять что существует **тренд цветов вокруг него**.


![](/i/smw_bg_block.png)


Мы **предскажем**, что в кадре будут **распространятся цвета по вертикали**, то есть цвета пикселей о которых мы не знаем в этой областе **будут содержать цвета соседей**.


![](/i/smw_bg_prediction.png)


Наше **предсказание может быть неверным**, по этому нам надо применить этот метод (**внутреннее предсказание**), а затем **вычесть реальные числа цветов**, что дает нам остаточный разедел и дает нам более сжимаемою матрицу по сравнению с оригиналой.


![](/i/smw_residual.png)


> #### Практика: проверка внутренних предсказаний

> Вы можете [зделать видео с макро разделами и их предскозаниями в ffmpeg.](/encoding_pratical_examples.md#generate-debug-video) Пожалуйста проверите документацию ffmpeg что бы понять [значение каждего блока цвета](https://trac.ffmpeg.org/wiki/Debug/MacroblocksAndMotionVectors#AnalyzingMacroblockTypes).

>

> ![внутринее предсказания (макро разделы) с ffmpeg](/i/macro_blocks_ffmpeg.png "внутринее предсказания (макро разделы) с ffmpeg")

>

> Так же можно использовать [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (програма платная, но есть бесплатная, пробная версия, которая ограничивает пользу на первые 10 кадров).

>

> ![внутринее предсказания intel video pro analyzer](/i/intra_prediction_intel_video_pro_analyzer.png "внутринее предсказания intel video pro analyzer")


# Как действует видео кодек?


## Что? Почему? Как?


**Что такое видео кодек?** Это система, программная или физическая, котороя сжимает или разжимает цифровое видео. **За чем?** Обществу, и в свою очередь рынку нужно видео высокого качества при ограниченом обьеме передачы или хренения информации. Помните когда мы [высчитали нужный обьем передачи](#основные-термины) для видео у которого 30 кадро на секунду, с битовой глубеной 24 бита и при разрешение 480х240? Это было **82.944mbps** без компресии. Только так можно передовать HD/FullHD/4K видео к телевизору или по интернету. **Как?** Мы провидем поверхностный обзор главныч техник здесь.


> **Кодек или контейнер?**

>

> Очень часто путается цыфровой видео кодек и [цыфровой видео контейнер](https://en.wikipedia.org/wiki/Digital_container_format). **Контейнер** можно представлять как оберток который содержит метаданные о видео (и возможно о звуке). **Сжатое видео** можно представить как его дoставочное содержaние.

>

> Обычно, расширение файла указывает тип контейнера. Например, файл `video.mp4` скорее всяго контейнер **[MPEG-4 Part 14](https://en.wikipedia.org/wiki/MPEG-4_Part_14)**, а файл с названием `video.mkv` скорее всяго контейнер **[matroska](https://en.wikipedia.org/wiki/Matroska)**. Что бы быть уверенным, можно использовать [ffmpeg или mediainfo](/encoding_pratical_examples.md#inspect-stream).


## History


Прежде чем мы углубимся во механизмы универсального кодека, давайте посмотрим в прошлое, чтобы немного лучше понять некоторые старые видеокодеки.


Видео кодек [H.261](https://en.wikipedia.org/wiki/H.261) официально родился в 1990, и был устроен работать при **обемене информации скоростью 64 kbit/s**. Уже используют методы на подобее цветовой субдесктирезации, макро блоки е т.д. В 1995 году, выпустили кодек **H.263** - этот стандарт прожил до 2001ого, время на пратижение которого на дним постоянно работали и улучшали.



В 2003 году была завершена первая версия **H.264 / AVC**. В том же году компания под названием **TrueMotion** выпустила свой видеокодек **без лицензионных отчислений** для сжатия видео с потерями под названием **VP3**. В 2008 году **Google купил** эту компанию, выпустив **VP8** в том же году. В декабре 2012 года Google выпустил **VP9**, и он **поддерживается примерно на ¾ из всех браузеров** (включая мобильные устройства).



**[AV1](https://en.wikipedia.org/wiki/AOMedia_Video_1)** - это новый **бесплатный кодек**, с открытым кодом, который разрабатывается [Альянсом открытых медиа (AOMedia)](http://aomedia.org/), в которую входят **компании: Google, Mozilla, Microsoft, Amazon, Netflix, AMD, ARM, NVidia, Intel и Cisco** и другие. **Первая версия** 0.1.0 эталонного кодека **была опубликована 7 апреля 2016 года**.


![история кодеков](/i/codec_history_timeline.png "история кодеков")

> #### Рождение AV1

>

> В начале 2015 года Google работали над [VP10](https://en.wikipedia.org/wiki/VP9#Successor:_from_VP10_to_AV1), Xiph (Mozilla) работали над [Daala](https://xiph.org/daala/) и Cisco открыли свой бесплатный видеокодек под названием [Thor](https://tools.ietf.org/html/draft-fuldseth-netvc-thor-03).

>

> Затем MPEG LA объявили годовые ограничения для HEVC (H.265) и сtoймость использованья в 8 раз выше, чем H.264. Вскоре они снова изменили правила:

> * **нет годового лимита**,

> * **плата за контент**, (0,5% от выручки) и

> * **Плата за единицу продукции примерно в 10 раз выше, чем h264**.

>

> [Альянс для открытых медиа](http://aomedia.org/about-us/) был создан производителями оборудованья (Intel, AMD, ARM, Nvidia, Cisco), контент доставчиками (Google, Netflix, Amazon) создателями враузеров (Google, Mozilla) и другими.

>

> У компаний была общая цель - бесплатный видео кодек, результат чаго является AV1, у которого [патентная лицензия на много проще](http://aomedia.org/license/patent/). **Тимоти Б. Терриберри** сделал потрясающую презентацию, которая является источником этого раздела, о [концепции AV1, модели лицензии и ее текущем состоянии](https://www.youtube.com/watch?v=lzPaldsmJbk ).

>

> Вы будете удивлены, узнав что возможно **проанализировать кодек AV1 через браузер**: http://aomanalyzer.org/

>

>![браузерный анализатор av1](/i/av1_browser_analyzer.png "браузерный анализатор av1")

>

> PS: Если вы хотите узнать больше об истории кодеков, взгляните на [патенты для сжатия видео](https://www.vcodex.com/video-compression-patents/).


## Общий кодек


Сейчас мы попытаемся описать **основные механизмы универсального видеокодека**, концепций которые полезны и используются в современных кодеках, на примере VP9, ​​AV1 и HEVC. Это будут упрощенные схемы, хотя иногда мы будем использовать реальные примеры (в основном по отношению к H.264) для демонстрации техники.


## 1-й шаг - разбиение изображения


Первым шагом действия кодека является **разделение кадра** на несколько **разделов, подразделов** и т.д.


![разделение изображений](/i/picture_partitioning.png "разделение изображений")


**Зачем?** Есть много причин - разделяя картинку, мы можем точнее обрабатывать прогнозы, используя маленькие разделы для маленьких движущихся частей видео и большие разделы для статического фона.


Обычно кодеки **организуют эти разделы** в срезы (или фрагменты), макро (или блоки схемы кодирования) и множество подразделов. Максимальный размер этих разделов варьируется, HEVC устанавливает 64x64, в то время как AVC использует 16x16, но подразделы могут достигать размеров 4x4.


Вы помните **разные типы кадров**? Возможно **применить эти идеи и к блокам**, поэтому у нас могут быть I-Slice, B-Slice, I-Macroblock и т.д.


> ### Практика: проверка разделов

> Мы можем использовать [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (программа платная, хотя есть бестплатная версия где можно проанализировать первых десять кадров). Вот [разделы VP9](/encoding_pratical_examples.md#transcoding).

>

> ![разделы VP9 intel video pro analyzer ](/i/paritions_view_intel_video_pro_analyzer.png "разделы VP9 intel video pro analyzer")


## 2-й шаг - предсказания


Как только у нас есть разделы, мы можем использовать их для предскозаний. Для [межкадрового предсказания](#временная-избыточность-меж-предскозание) нам нужно **использовать векторы движения и остаток**, а для [внутрекадрового предсказания](#пространственная-избыточность-внутреннее-предсказание) мы будем **использаовать предсказанное направление и остаток**.


## 3-й шаг - трансформация


После того, как мы получим остаточный блок (`предсказанный раздел - реальный раздел`), мы можем **трансформировать его** образом которым даст нам знать, какие **пиксели мы можем выбросить**, сохраняя при этом **общее качество**. Есть некоторые трансформации которые тут нам помогут.


Хотя есть [другие трансформации](https://en.wikipedia.org/wiki/List_of_Fourier-related_transforms#Discrete_transforms), мы более подробно рассмотрим дискретную косинусную трансформацию, ДСТ (DCT). Основные функции [**DCT**](https://en.wikipedia.org/wiki/Discrete_cosine_transform):


* **Переводит блоки пикселей** в **блоки одинакового размера частотных коэффициентов**.

* **Сжимает** энергию, облегчая устранение пространственной избыточности.

* Являетсья **обратимым процессом**, например, вы можете вернуться к пикселям.


> 2 февраля 2017 г. Синтра Р. Дж. И Байер Ф. М. опубликовали свою статью [ДСТ-подобное преобразование для сжатия изображений требует только 14 дополнений](https://arxiv.org/abs/1702.00817).


Не беспокойтесь, если вы не поняли преимуществ каждого пункта, мы попытаемся провести несколько экспериментов, чтобы понять порцесс подробнее.


Давайте возьмем следующий **блок пикселей** (8x8):


![матрица значений пикселей](/i/pixel_matrice.png "матрица значений пикселей")


Который рендерится как изображение (8x8):


![матрица значений пикселей](/i/gray_image.png "матрица значений пикселей")


Когда мы **применяем ДСТ** к этому блоку пикселей, мы получаем **блок коэффициентов** (8x8):


![значения коэффициентов](/i/dct_coefficient_values.png "значения коэффициентов")


И если мы отрендерим этот блок коэффициентов, мы получим это изображение:


![изображение коэффициентов dct](/i/dct_coefficient_image.png "изображение коэффициентов dct")


Как видно, это не похоже на исходное изображение, и похоже что **первый коэффициент** очень отличается от всех остальных. Этот первый коэффициент известен как коэффициент DC, представляя себе **все выборки** во входном массиве, что-то **на подобие среднего числа**.


Этот блок коэффициентов обладает интересным свойством, заключающимся в том, что он отделяет высокочастотные компоненты от низкочастотных.


![свойство частотных коэффициентов ДСТ](/i/dctfrequ.jpg "свойство частотных коэффициентов ДСТ")


На изображении **большая часть энергии** будет сосредоточена на [**более низких частотах**](https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labour/zinke/mk/mpeg2beg/whatisit.htm), поэтому если мы трансформируем изображение в его частотные компоненты и **отбросим более высокие частотные коэффициенты**, мы можем **уменьшить объем данных** необходимо описать изображение, не жертвуя качеством слижком сильно.


> частота означает, насколько быстро меняется сигнал


Давайте попробуем применить знания, которые мы получили в тесте, трансформоруя исходное изображение в его частоту (блок коэффициентов), используя ДСТ, а затем отбрасывая часть наименее важных коэффициентов.


Сначала мы конвертируем его в **частотную область**.


![значения коэффициентов](/i/dct_coefficient_values.png "значения коэффициентов")


Далее мы отбрасываем часть (67%) коэффициентов, в основном нижнюю правую часть.


![Обнуленные коэффициенты](/i/dct_coefficient_zeroed.png "Обнуленные коэффициенты")


Наконец, мы восстанавливаем изображение из этого отброшенного блока коэффициентов (помните, оно должно быть обратимым) и сравниваем его с оригиналом.


![оригинал напротив квантованного](/i/original_vs_quantized.png "оригинал напротив квантованного")


Как видно, оно почоже на исходное изображение, но в нем есть много отличий от оригинала. Мы **выбрасили 67,1875%** и все же смогли получить хотя бы что-то похожее на оригинал. Мы могли бы более разумно отбросить коэффициенты, чтобы получить лучшее качество изображения, но это следующая тема.


> **Каждый коэффициент формируется с использованием всех пикселей**

>

> Важно отметить, что каждый коэффициент не отображается напрямую на один пиксель, а представляет собой взвешенную сумму всех пикселей. Этот удивительный график показывает, как рассчитывается первый и второй коэффициент с использованием весов, уникальных для каждого индекса.

>

>![расчет ДСТ](/i/Applicat.jpg "расчет ДСТ")

>

> Источник: https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm

>

> Вы также можете попытаться [визуализировать ДСТ, взглянув на это изображение](/dct_better_explained.ipynb). Например, вот создается [символ "A"](https://en.wikipedia.org/wiki/Discrete_cosine_transform#Example_of_IDCT) с помощю каждого веса коэффициента.

>

>! [] (https://upload.wikimedia.org/wikipedia/commons/5/5e/Idct-animation.gif)





<br/>


> ### Практика: выбрасывание разных коэффициентов

> Вы можете поигратся с [ДСТ трансформациями тут](/uniform_quantization_experience.ipynb).


## 4-й шаг - квантование


Когда мы выбрасываем коэффициенты, на последнем шаге (трансформация) мы делали некоторую форму квантования. На этом этапе мы решили потерять информацию или, проще говоря, мы **квантовали коэффициенты для достижения сжатия**.


Как мы можем квантовать блок коэффициентов? Одним простым методом было бы равномерное квантование, где мы берем блок, **делим его на одно значение** (10) и округляем это значение.


![квантовать](/i/quantize.png "квантовать")


Как мы можем **обратить** (переквантовать) этот блок коэффициентов? Мы можем **умножить одним и тем же значением** (10), которым мы разделили.


![повторное квантование](/i/re-quantize.png "повторное квантование")


Этот **подход не лучший**, потому что он не учитывает важность каждого коэффициента. Мы могли бы использовать **матрицу квантователей** вместо одного значения, эта матрица может использовать свойство ДСТ, квантовая больше нижнего правого и меньше верхнего левого, [JPEG использует аналогичный подход](https://www.hdm-stuttgart.de/~maucher/Python/MMCodecs/html/jpegUpToQuant.html). Вы можете проверить [исходный код, чтобы увидеть эту матрицу](https://github.com/google/guetzli/blob/master/guetzli/jpeg_data.h#L40).


> ### Практока: квантование

> Вы можете поиграть с [квантованием] (/ dct_experiences.ipynb).


## 5-й шаг - энтропийное кодирование


После того, как мы квантовали данные (блоки изображения / фрагменты / кадры), мы все еще можем сжимать их без потерь. Существует много способов (алгоритмов) сжатия данных. Мы собираемся кратко познакомиться с некоторыми из них, для более глубокого понимания вы можете прочитать удивительную книгу [Понимание сжатия: сжатие данных для современных разработчиков](https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/).


### VLC кодирование:


Предположим, у нас есть поток символов: **a**, **e**, **r** и **t**, и их вероятность (от 0 до 1) представлена ​​этой таблицей.


| | a | e | r | t |

|-------------|-----|-----|------|-----|

| вероятность | 0.3 | 0.3 | 0.2 | 0.2 |


Мы можем присвоить уникальные коды (предпочтительно маленькие) наиболее вероятным, а более крупные коды наименее вероятным.


| | a | e | r | t |

|-------------|-----|-----|------|-----|

| вероятность | 0.3 | 0.3 | 0.2 | 0.2 |

| код | 0 | 10 | 110 | 1110 |


Давайте сожмем поток **eat**, предполагая что мы потратим 8 битов на каждый символ, то в общей сложности мы тратим **24 бита** без какого-либо сжатия. Но в случае замены каждого символа на его код мы можем сэкономить место.


Первый шаг заключается в кодировании символа **e**, который равен `10`, второй символ **а** добавляется что бы получить `[10][0]` и, наконец, третий символ **t**, который делает наш окончательный сжатый поток битов равным `[10][0][1110]` или `1001110`, которому нужно только **7 битов** (т.е 3.4 раза меньше места, чем оригинальный поток).


Обратите внимание, что каждый код должен иметь уникальный префикс код [Хаффман может помочь вам найти эти номера](https://en.wikipedia.org/wiki/Huffman_coding). Хотя у этого метода есть проблемы, есть [видеокодеки, которые все еще предлагают](https://en.wikipedia.org/wiki/Context-adaptive_variable-length_coding) его, и это алгоритм для многих приложений, который требует сжатия.


Кодер и декодер **должны знать** таблицу символов с ее кодом, поэтому вам также необходимо отправлять таблицу.


### Арифметическое кодирование:


Давай скажим что у нас есть поток символов: **a**, **e**, **r**, **s**, **t** и их вероятность показанна на таблице:


| | a | e | r | s | t |

|-------------|-----|-----|------|------|-----|

| вероятность | 0.3 | 0.3 | 0.15 | 0.05 | 0.2 |


Зная об этой таблице, мы можем построить области со всеми возможными сомволами, отсортированные теми которые появляются чаще всяго. 


![начальный арифметический диапазон](/i/range.png "начальный арифметический диапазон")


Теперь давайте закодируем поток **eat**, мы выбираем первый символ **a**, который находится в новом поддиапазоне **0.3 до 0.6** (но не включен), и мы берем этот поддиапазон и снова разделяем его, используя те же пропорции, которые использовались ранее, но в этом новом диапазоне.


![второй поддиапазон](/i/second_subrange.png "второй поддиапазон")


Давайте продолжим кодировать наш поток **eat**, мы выберем второй символ **a**, который находится в новом поддиапазоне **0.3 до 0.39**, а затем мы берем наш последний символ **t**, повторяя процесс что бы получить последний поддиапазон **0.354 до 0.372**.


![окончательный арифметический диапазон](/i/arithimetic_range.png "конечный арифметический диапазон")


Нам просто нужно выбрать число в последнем поддиапазоне **0.354 до 0.372**, давайте выберем **0.36**, но мы можем выбрать любое число в этом поддиапазоне. С **только** этим номером мы сможем восстановить наш оригинальный поток **eat**. Если подумать об этом, мы как бы нарисовали линию в пределах диапазонов для кодирования нашего потока.


![окончательный обход диапазона](/i/range_show.png "окончательный обход диапазона")


**Обратный процесс** (т.е. декодирование) одинаково прост, с нашим числом **0,36** и нашим исходным диапазоном мы можем запустить тот же процесс, но теперь используя это число, чтобы показать поток, закодированный за этим номером.


С первым диапазоном мы заметили что наше число соответствует срезу, поэтому это наш первый символ, теперь мы снова разбиваем этот поддиапазон, выполняя тот же процесс что и раньше, и мы можем заметить, что **0.36** соответствует символу **a** и после того, как мы повторим процесс, мы подходим к последнему символу **t** (формируя наш оригинальный кодированный поток *eat*).


Кодер и декодер **должны знать** таблицу вероятностей символов, поэтому вам необходимо отправлять таблицу.


Не плохо, правда? Люди чертовски умны, чтобы придумать такое решение, некоторые [видеокодеки используют](https://en.wikipedia.org/wiki/Context-adaptive_binary_arithmetic_coding) эту технику (или, по крайней мере, предлагают ее в качестве опции).


Идея состоит в том, чтобы сжать без потерь квантованный поток битов, наверняка в этой статье отсутствуют тонны деталей, причин, компромиссов и т. Д. Но [вы должны узнать больше](https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/) в качестве разработчика. Более новые кодеки пытаются использовать различные [алгоритмы энтропийного кодирования, наподобие ANS.](https://en.wikipedia.org/wiki/Asymmetric_Numeral_Systems)


> ### Практика: CABAC vs CAVLC

> Вы можете [создать два потока, один с CABAC and другой с CAVLC](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#cabac-vs-cavlc) and **сравнить время** занятое для их создание, а так же **конечный размер файла**.


## 6-й шаг - формат битового потока


После того, как мы выполнили все эти шаги, нам нужно **упаковать сжатые кадры и контекст к этим шагам**. Нам необходимо сообщить декодеру **о решениях, принятых кодером**, например битовая глубина, цветовое пространство, разрешение, информация о предсказаниях (векторы движения, направление внутреннего предсказания), профиль, уровень, частота кадров, тип кадра, номер кадра и многое другое.


Мы поверхностно изучим поток битов H.264. Наш первый шаг - [создать минимальный битовый поток H.264 <sup>*</sup>](/encoding_pratical_examples.md#generate-a-single-frame-h264-bitstream), что мы можем сделать это с помощью нашего собственного репозитория и [ffmpeg](http://ffmpeg.org/).


```

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

```


> <sup>*</sup> ffmpeg по умолчанию добавляет все параметры кодирования в виде **SEI NAL** - вскоре мы определим, что такое NAL.


Эта команда сгенерирует необработанный поток битов h264 с **одиночным кадром**, 64x64, с цветовым пространством yuv420 и с использованием следующего изображения в качестве кадра.


>![используемый кадр для генерации минимального битового потока h264](/i/minimal.png "используемый кадр для генерации минимального битового потока h264")


### H.264 битовый поток


Стандарт AVC (H.264) определяет, что информация будет отправляться в **макрокадрах** (в смысле сети), называемых **[NAL](https://en.wikipedia.org/wiki/Network_Abstraction_Layer)** (Сетевой Уровень Aбстракции). Основной целью NAL является обеспечение "дружественного к сети" представления видео, этот стандарт должен работать на телевизорах (на основе потоков), в Интернете (на основе пакетов) и т.д.


![Блоки NAL H.264](/i/nal_units.png "блоки NAL H.264")


Существует **[маркер синхронизации](https://en.wikipedia.org/wiki/Frame_synchronization)** для определения границ единиц NAL. Каждый маркер синхронизации содержит значение `0x00 0x00 0x01`, за исключением самого первого, который является` 0x00 0x00 0x00 0x01`. Если мы запустим **hexdump** в сгенерированном потоке битов h264, мы сможем идентифицировать как минимум три NAL в начале файла.


![маркер синхронизации на блоках NAL](/iminimal_yuv420_hex.png "маркер синхронизации на блоках NAL")


Как мы уже говорили, декодеру надо знать не только данные изображения, но также детали видео, фрейма, цвета, используемые параметры и другие. **Первый байт** каждого NAL определяет его категорию и **тип**.


| NAL type id | Description |

|--- |---|

| 0 | Undefined |

| 1 | Coded slice of a non-IDR picture |

| 2 | Coded slice data partition A |

| 3 | Coded slice data partition B |

| 4 | Coded slice data partition C |

| 5 | **IDR** Coded slice of an IDR picture |

| 6 | **SEI** Supplemental enhancement information |

| 7 | **SPS** Sequence parameter set |

| 8 | **PPS** Picture parameter set |

| 9 | Access unit delimiter |

| 10 | End of sequence |

| 11 | End of stream |

| ... | ... |


Обычно первый NAL битового потока представляет собой **SPS**, этот тип NAL отвечает за информирование общих переменных кодирования, таких как **профиль**, **уровень**, **разрешение** и другие.


Если мы пропустим первый маркер синхронизации, мы можем декодировать **первый байт**, чтобы узнать, какой **тип NAL** является первым.


Например, первый байт после маркера синхронизации равен `01100111`, где первый бит (`0`) находится в поле **forbidden_zero_bit**, следующие 2 бита (`11`) сообщают нам поле **nal_ref_idc** который указывает если этот является NAL опорным полем или нет, а остальные 5 битов (`00111`) информируют нас о поле **nal_unit_type**, в данном случае это **SPS** (7) единица NAL.


Второй байт (`binary = 01100100, hex = 0x64, dec = 100`) SPS NAL - это поле **profile_idc**, которое показывает профиль, который использовал кодировщик, в этом случае мы использовали **[ограниченный высокий профиль](https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles)**, это высокий профиль без поддержки B (двунаправленных) срезов.


![Двоичное представление SPS](/i/minimal_yuv420_bin.png "двоичное представление SPS")


Когда мы читаем спецификацию потока битов H.264 для SPS NAL, мы найдем много значений, например, **parameter name**, **category** и **description**, давайте посмотрим на `pic_width_in_mbs_minus_1` и поля `pic_height_in_map_units_minus_1`.


| Parameter name | Category | Description |

|--- |---|---|

| pic_width_in_mbs_minus_1 | 0 | ue(v) |

| pic_height_in_map_units_minus_1 | 0 | ue(v) |


> **ue(v)**: целое число без знака [Exp-Golomb-кодированный](https://pythonhosted.org/bitstring/exp-golomb.html)


Если мы немного посчитаем значения этих полей, мы получим **разрешение**. Мы можем представить `1920 x 1080`, используя `pic_width_in_mbs_minus_1` со значением `119 ((119 + 1) * macroblock_size = 120 * 16 = 1920)`, опять же экономя место, вместо того, чтобы кодировать `1920`, как мы это сделали с `119`.


Если мы продолжим проверять наше созданное видео в двоичном виде (например: `xxd -b -c 11 v/minimal_yuv420.h264`), мы можем перейти к последнему NAL, который является самим кадром.


![h264 idr заголовок слайса](/i/slice_nal_idr_bin.png "h264 idr заголовок слайса")


Мы можем видеть его первые 6 байтовых значений: `01100101 10001000 10000100 00000000 00100001 11111111`. Поскольку мы уже знаем, что первый байт говорит нам о том, что это за тип NAL, в данном случае (`00101`) это **IDR Slice (5)**, и мы можем проверить его:


![Спецификация заголовка слайса h264](/i/slice_header.png "Спецификация заголовка слайса h264")


Используя информацию спецификации, мы можем декодировать, какой тип слайса (**slice_type**), номер кадра (**frame_num**) среди других важных полей.


Чтобы получить значения некоторых полей (`ue (v), me (v), se (v) или te (v)`)), нам нужно декодировать его, используя специальный декодер под названием [Exponential-Golomb](https://pythonhosted.org/bitstring/exp-golomb.html), этот метод **очень эффективен для кодирования значений переменных**, главным образом, когда существует много значений по умолчанию.


> Значения **slice_type** и **frame_num** этого видео равны 7 (I срез) и 0 (первый кадр).


Мы можем видеть **поток битов как протокол**, и если вы хотите или вам надо узнать больше об этом потоке битов, обратитесь к [спецификации МСЭ H.264](http://www.itu.int/rec/T-REC-H.264-201610-I) Вот макросхема, которая показывает, где находятся данные изображения (сжатые YUV).


![Макросхема битового потока h264](/ih264_bitstream_macro_diagram.png "Макросхема битового потока h264")


Мы можем исследовать другие битовые потоки, такие как [битовый поток VP9](https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf), [H.265 (HEVC)](http://handle.itu.int/11.1002/1000/11885-en?locatt=format:pdf) или даже наш **новый лучший друг** [**AV1** поток битов](https://medium.com/@mbebenita/av1-bitstream-analyzer-d25f1c27072b#.d5a89oxz8

), [они все похожи? Нет](http://www.gpac-licensing.com/2016/07/12/vp9-av1-bitstream-format/), но как только вы выучите один, вы легко сможете понять другие.


> ### Практика: Проверка битовога потока H.264

> Мы можем [создать однокадровое видео](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#generate-a-single-frame-video) и использовать [mediainfo](https://en.wikipedia.org/wiki/MediaInfo) для проверки потока битов H.264. Вы даже можете увидеть [исходный код, который анализирует битовый поток h264 (AVC)](https://github.com/MediaArea/MediaInfoLib/blob/master/Source/MediaInfo/Video/File_Avc.cpp).

>

> ![mediainfo показывает поток битов h264](/i/mediainfo_details_1.png "mediainfo показывает поток битов h264")

>

> Мы также можем использовать [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer), который платный, хотя существует бесплатная пробная версия, которая ограничивает вас только первые 10 кадров (которых для учебных целей должно быть достаточно).

>

> ![intel video pro analyzer показывает поток битов h264](/i/intel-video-pro-analyzer.png "intel video pro analyzer показывает поток битов h264")


## Обзор


Мы заметим, что многие из **современных кодеков используют ту же модель, которую мы изучили**. Можно посмотреть на блок-схему видеокодека Thor и увидеть что она содержит все шаги, которые мы изучали. Идея состоит в том, что теперь вы в состоянии лучше понять инновации и документы в этой области.


![thor_codec_block_diagram](/i/thor_codec_block_diagram.png "thor_codec_block_diagram")


Ранее мы рассчитывали, что нам потребуется [139 ГБ дискового пространства для хранения видеофайла одного часа в длинне при разрешении 720p и 30 к/с](#цветовая-субдискретизация). С помощю методов которые описаны здесь, такие как **меж и внутреннее предсказание, трансформации, квантование, энтропийное кодирование и другие**, то же видео воспринимаемого качества можно сжать до **только 367.82 МБ**.


> Мы решили использовать **0.031 бит на пиксель** на основе примера видео, представленного здесь.


## Как H.265 достигает лучшей степени сжатия, чем H.264?


Зная больше о том, как работают кодеки, легко понять как новые кодеки способны обеспечивать более высокое разрешение с меньшим количеством битов.


Мы сравним AVC и HEVC, помня что это почти всегда компромисс между большим количеством циклов ЦП (сложность) и степенью сжатия.


HEVC имеет больше каличество **разделов** (и **подразделов**), которые так же и больше в размере чем AVC, больше **направлений внутреннего предсказания**, **улучшенное энтропийное кодирование** и более, все эти улучшения дали H.265 способность сжимать на 50% больше, чем H.264.


![h264 против h265](/i/avc_vs_hevc.png "H.264 против H.265")


# Онлайн трансляция

## Общая архитектура


! [общая архитектура](/i/general_architecture.png "общая архитектура")


[TODO]


## Прогрессивная загрузка и адаптивная потоковая передача


![Прогрессивная загрузка](/i/progressive_download.png "Прогрессивная загрузка")


![Адаптивный поток](/i/adaptive_streaming.png "Адаптивный поток")


[TODO]


## Защита контента


Мы можем использовать **простую систему токенов** для защиты контента. Запрос видео без токена будет запрещщен CDN-ом, в то время как пользователь с действительным токеном может воспроизводить контент. Он работает почти так же, как и большинство систем веб-аутентификации.


![защита токена](/i/token_protection.png "token_protection")


Использую эту систему токенов позволяет пользователю загружать видео и распространять его. Затем можно использовать систему **DRM (управление цифровыми правами)**, чтобы избежать этого.


![drm](/i/drm.png "drm")


В реальных производственных системах люди часто используют оба метода для обеспечения авторизации и аутентификации.


### DRM

#### Основные системы


* FPS - [**FairPlay Streaming**](https://developer.apple.com/streaming/fps/)

* PR - [**PlayReady**](https://www.microsoft.com/playready/)

* WV - [**Widevine**](http://www.widevine.com/)



#### Какой?


DRM зто система цифровых прав, это способ **обеспечить защиту авторских прав на цифровых материалов** - например, цифровое видео и аудио. Хотя он используется во многих местах [он не является общепринятым](https://en.wikipedia.org/wiki/Digital_rights_management#DRM-free_works).


#### Зачем?


Создатель контента (в основном, студии) хотят защитить свою интеллектуальную собственность от копирования, чтобы предотвратить несанкционированное распространение цифрового контента.


#### Как?


Мы собираемся описать абстрактную и общую форму DRM в очень упрощенном виде.


Учитывая **контент C1** (т.е. потоковое видео hls или dash), с **проигрывателем P1** (т.е. shaka-clappr, exo-player или ios) в **устройстве D1** (т.е. смартфоне , Телевизор, планшет или настольный компьютер / ноутбук) с использованием **DRM системы DRM1** (widevine, playready или FairPlay).


Контент C1 зашифрован с помощью **симметричного ключа K1** от системы DRM1, генерируя **зашифрованный контент C'1**.


![drm general flow](/i/drm_general_flow.jpeg "drm general flow")


Проигрыватель P1 устройства D1 имеет два ключа (асимметричные): **закрытый ключ PRK1** (этот ключ защищен <sup>1</sup> и известен только **D1**) и **открытый ключ PUK1**.


> ** <sup> 1 </ sup> защищен **: эта защита может быть ** с помощью аппаратного обеспечения **, например, этот ключ может храниться в специальном (только для чтения) чипе, который работает как [черный box] (https://en.wikipedia.org/wiki/Black_box), чтобы обеспечить расшифровку, или ** с помощью программного обеспечения ** (менее безопасно), система DRM предоставляет средства, чтобы узнать, какой тип защиты имеет данное устройство.



Когда ** игрок P1 хочет воспроизвести ** контент ** C'1 **, он должен иметь дело с ** DRM-системой DRM1 **, предоставив свой открытый ключ ** PUK1 **. DRM-система DRM1 возвращает ** ключ K1 в зашифрованном виде ** с открытым ключом клиента ** PUK1 **. Теоретически, этот ответ - это то, что ** только D1 способен расшифровать **.


`K1P1D1 = enc (K1, PUK1)`


**P1** использует свою локальную систему DRM (это может быть [SOC](https://en.wikipedia.org/wiki/System_on_a_chip), специализированное аппаратное или программное обеспечение), эта система **может дешифровать** контент, и используя свой закрытый ключ PRK1, может расшифровать **симметричный ключ K1 от K1P1D1** и **воспроизвести C'1**. В лучшем случае ключи не выставляются через ОЗУ.


 ``,

 K1 = dec (K1P1D1, PRK1)


 P1.play (dec (C'1, K1))

 ``,


![поток drm декодера](/i/drm_decoder_flow.jpeg "поток drm декодера")


# Как использовать Jupyter


Убедитесь, что у вас установлен **docker** и просто запустите `./s/ start_jupyter.sh` и следуйте инструкциям на терминале.


# Конференции


* [DEMUXED](https://demuxed.com/) - вы можете [проверить последние 2 презентации.](Https://www.youtube.com/channel/UCIc_DkRxo9UgUSTvWVNCmpA).


# Ссылки


Здесь самый богатый контент, вся информация которую мы видели в этом тексте, была извлечена, основана или вдохновлена. Вы можете углубить свои знания с помощью этих удивительных ссылок, книг, видео и т. д.


Онлайн курсы и учебные пособия:


* https://www.coursera.org/learn/digital/

* https://people.xiph.org/~tterribe/pubs/lca2012/auckland/intro_to_video1.pdf

* https://xiph.org/video/vid1.shtml

* https://xiph.org/video/vid2.shtml

* http://slhck.info/ffmpeg-encoding-course

* http://www.cambridgeincolour.com/tutorials/camera-sensors.htm

* http://www.slideshare.net/vcodex/a-short-history-of-video-coding

* http://www.slideshare.net/vcodex/introduction-to-video-compression-13394338

* https://developer.android.com/guide/topics/media/media-formats.html

* http://www.slideshare.net/MadhawaKasun/audio-compression-23398426

* http://inst.eecs.berkeley.edu/~ee290t/sp04/lectures/02-Motion_Compensation_girod.pdf


Books:


* https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/ref=sr_1_1?s=books&ie=UTF8&qid=1486395327&sr=1-1

* https://www.amazon.com/H-264-Advanced-Video-Compression-Standard/dp/0470516925

* https://www.amazon.com/Practical-Guide-Video-Audio-Compression/dp/0240806301/ref=sr_1_3?s=books&ie=UTF8&qid=1486396914&sr=1-3&keywords=A+PRACTICAL+GUIDE+TO+VIDEO+AUDIO

* https://www.amazon.com/Video-Encoding-Numbers-Eliminate-Guesswork/dp/0998453005/ref=sr_1_1?s=books&ie=UTF8&qid=1486396940&sr=1-1&keywords=jan+ozer


Onboarding material:


* https://github.com/Eyevinn/streaming-onboarding

* https://howvideo.works/

* https://www.aws.training/Details/eLearning?id=17775

* https://www.aws.training/Details/eLearning?id=17887

* https://www.aws.training/Details/Video?id=24750


Bitstream Specifications:


* http://www.itu.int/rec/T-REC-H.264-201610-I

* http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=12904&lang=en

* https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf

* http://iphome.hhi.de/wiegand/assets/pdfs/2012_12_IEEE-HEVC-Overview.pdf

* http://phenix.int-evry.fr/jct/doc_end_user/current_document.php?id=7243

* http://gentlelogic.blogspot.com.br/2011/11/exploring-h264-part-2-h264-bitstream.html

* https://forum.doom9.org/showthread.php?t=167081

* https://forum.doom9.org/showthread.php?t=168947


Software:


* https://ffmpeg.org/

* https://ffmpeg.org/ffmpeg-all.html

* https://ffmpeg.org/ffprobe.html

* https://trac.ffmpeg.org/wiki/

* https://software.intel.com/en-us/intel-video-pro-analyzer

* https://medium.com/@mbebenita/av1-bitstream-analyzer-d25f1c27072b#.d5a89oxz8


Non-ITU Codecs:


* https://aomedia.googlesource.com/

* https://github.com/webmproject/libvpx/tree/master/vp9

* https://people.xiph.org/~xiphmont/demo/daala/demo1.shtml

* https://people.xiph.org/~jm/daala/revisiting/

* https://www.youtube.com/watch?v=lzPaldsmJbk

* https://fosdem.org/2017/schedule/event/om_av1/

* https://jmvalin.ca/papers/AV1_tools.pdf


Encoding Concepts:


* http://x265.org/hevc-h265/

* http://slhck.info/video/2017/03/01/rate-control.html

* http://slhck.info/video/2017/02/24/vbr-settings.html

* http://slhck.info/video/2017/02/24/crf-guide.html

* https://arxiv.org/pdf/1702.00817v1.pdf

* https://trac.ffmpeg.org/wiki/Debug/MacroblocksAndMotionVectors

* http://web.ece.ucdavis.edu/cerl/ReliableJPEG/Cung/jpeg.html

* http://www.adobe.com/devnet/adobe-media-server/articles/h264_encoding.html

* https://prezi.com/8m7thtvl4ywr/mp3-and-aac-explained/

* https://blogs.gnome.org/rbultje/2016/12/13/overview-of-the-vp9-video-codec/

* https://videoblerg.wordpress.com/2017/11/10/ffmpeg-and-how-to-use-it-wrong/


Video Sequences for Testing:


* http://bbb3d.renderfarming.net/download.html

* https://www.its.bldrdoc.gov/vqeg/video-datasets-and-organizations.aspx


Miscellaneous:


* https://github.com/Eyevinn/streaming-onboarding

* http://stackoverflow.com/a/24890903

* http://stackoverflow.com/questions/38094302/how-to-understand-header-of-h264

* http://techblog.netflix.com/2016/08/a-large-scale-comparison-of-x264-x265.html

* http://vanseodesign.com/web-design/color-luminance/

* http://www.biologymad.com/nervoussystem/eyenotes.htm

* http://www.compression.ru/video/codec_comparison/h264_2012/mpeg4_avc_h264_video_codecs_comparison.pdf

* http://www.csc.villanova.edu/~rschumey/csc4800/dct.html

* http://www.explainthatstuff.com/digitalcameras.html

* http://www.hkvstar.com

* http://www.hometheatersound.com/

* http://www.lighterra.com/papers/videoencodingh264/

* http://www.red.com/learn/red-101/video-chroma-subsampling

* http://www.slideshare.net/ManoharKuse/hevc-intra-coding

* http://www.slideshare.net/mwalendo/h264vs-hevc

* http://www.slideshare.net/rvarun7777/final-seminar-46117193

* http://www.springer.com/cda/content/document/cda_downloaddocument/9783642147029-c1.pdf

* http://www.streamingmedia.com/Articles/Editorial/Featured-Articles/A-Progress-Report-The-Alliance-for-Open-Media-and-the-AV1-Codec-110383.aspx

* http://www.streamingmediaglobal.com/Articles/ReadArticle.aspx?ArticleID=116505&PageNum=1

* http://yumichan.net/video-processing/video-compression/introduction-to-h264-nal-unit/

* https://cardinalpeak.com/blog/the-h-264-sequence-parameter-set/

* https://cardinalpeak.com/blog/worlds-smallest-h-264-encoder/

* https://codesequoia.wordpress.com/category/video/

* https://developer.apple.com/library/content/technotes/tn2224/_index.html

* https://en.wikibooks.org/wiki/MeGUI/x264_Settings

* https://en.wikipedia.org/wiki/Adaptive_bitrate_streaming

* https://en.wikipedia.org/wiki/AOMedia_Video_1

* https://en.wikipedia.org/wiki/Chroma_subsampling#/media/File:Colorcomp.jpg

* https://en.wikipedia.org/wiki/Cone_cell

* https://en.wikipedia.org/wiki/File:H.264_block_diagram_with_quality_score.jpg

* https://en.wikipedia.org/wiki/Inter_frame

* https://en.wikipedia.org/wiki/Intra-frame_coding

* https://en.wikipedia.org/wiki/Photoreceptor_cell

* https://en.wikipedia.org/wiki/Pixel_aspect_ratio

* https://en.wikipedia.org/wiki/Presentation_timestamp

* https://en.wikipedia.org/wiki/Rod_cell

* https://it.wikipedia.org/wiki/File:Pixel_geometry_01_Pengo.jpg

* https://leandromoreira.com.br/2016/10/09/how-to-measure-video-quality-perception/

* https://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping

* https://softwaredevelopmentperestroika.wordpress.com/2014/02/11/image-processing-with-python-numpy-scipy-image-convolution/

* https://tools.ietf.org/html/draft-fuldseth-netvc-thor-03

* https://www.encoding.com/android/

* https://www.encoding.com/http-live-streaming-hls/

* https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm

* https://www.lifewire.com/cmos-image-sensor-493271

* https://www.linkedin.com/pulse/brief-history-video-codecs-yoav-nativ

* https://www.linkedin.com/pulse/video-streaming-methodology-reema-majumdar

* https://www.vcodex.com/h264avc-intra-precition/

* https://www.youtube.com/watch?v=9vgtJJ2wwMA

* https://www.youtube.com/watch?v=LFXN9PiOGtY

* https://www.youtube.com/watch?v=Lto-ajuqW3w&list=PLzH6n4zXuckpKAj1_88VS-8Z6yn9zX_P6

* https://www.youtube.com/watch?v=LWxu4rkZBLw

* https://web.stanford.edu/class/ee398a/handouts/lectures/EE398a_MotionEstimation_2012.pdf


Report Abuse

Login or Register to edit or copy and save this text. It's free.