[🇺🇸](/README.md "English")
[🇨🇳](/README-cn.md "Simplified Chinese")
[🇯🇵](/README-ja.md "Japanese")
[🇮🇹](/README-it.md "Italian")
[🇰🇷](/README-ko.md "Korean")
[🇷🇺](/README-ru.md "Russian")
[🇧🇷](/README-pt.md "Portuguese")
[🇪🇸](/README-es.md "Spanish")

[![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 каналов")

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

У каждого канала определённое количество битов, так называема **битовая глубина**. Если у нас **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). Обратите внимание на размер файла и качество видео.

### Конспект

Эти кадры используются для **более эффективной компрессии**. Мы уведем как это происходит в следующем отделе, на не теперешний момент нам достаточно помнить что **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?version=7#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).

## История

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

Видео кодек [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/) был создан производителями оборудованья (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 через браузер**: https://arewecompressedyet.com/analyzer/
>
>![браузерный анализатор 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/