# Загрузка данных видео

> [!WARNING]
> Поддержка видео является экспериментальной и может быть изменена.

Наборы данных видео имеют столбцы типа [Video](/docs/datasets/v5.2.0/ru/package_reference/main_classes#datasets.Video), которые содержат объекты `torchcodec`.

> [!TIP]
> Для работы с наборами данных видео необходимо установить пакеты `torchcodec` и `ffmpeg`. Ознакомьтесь с руководством по [установке](https://github.com/meta-pytorch/torchcodec#installing-torchcodec), чтобы узнать, как их установить.

При загрузке набора данных с видео и обращении к столбцу с видео, видео декодируются как `torchcodec` Videos:

```py
>>> from datasets import load_dataset, Video

>>> dataset = load_dataset("path/to/video/folder", split="train")
>>> dataset[0]["video"]
<torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61d5a0>
```

> [!WARNING]
> Обращайтесь к набору данных видео сначала по индексу строки, а затем по столбцу `video` — `dataset[0]["video"]` — чтобы избежать создания всех объектов видео в наборе данных. В противном случае, если у вас большой набор данных, этот процесс может быть медленным и требовать много времени.

Справочник по загрузке любого типа набора данных см. в общем руководстве по загрузке.

## Чтение кадров

Обращайтесь к кадрам видео напрямую с помощью `VideoReader`, используя `next()`:

```python
>>> video = dataset[0]["video"]
>>> first_frame = video.get_frame_at(0)
>>> first_frame.data.shape
(3, 240, 320)
>>> first_frame.pts_seconds  # timestamp
0.0
```

Чтобы получить несколько кадров за один раз, можно вызвать `.get_frames_in_range(start: int, stop: int, step: int)`. Это вернёт пакет кадров. Это эффективный способ получить длинный список кадров. Подробнее о функциях для эффективного доступа к данным см. в [документации torchcodec](https://meta-pytorch.org/torchcodec/stable/generated/torchcodec.decoders.VideoDecoder.html):

```python
>>> import torch
>>> frames = video.get_frames_in_range(0, 6, 1)
>>> frames.data.shape
torch.Size([5, 3, 240, 320])
```

Также существует `.get_frames_played_in_range(start_seconds: float, stop_seconds: float)` для доступа ко всем кадрам, воспроизведённым в определённом временном диапазоне.

```python
>>> frames = video.get_frames_played_in_range(.5, 1.2)
>>> frames.data.shape
torch.Size([42, 3, 240, 320])
```

## Локальные файлы

Вы можете загрузить набор данных из пути к видео. Используйте функцию [cast_column()](/docs/datasets/v5.2.0/ru/package_reference/main_classes#datasets.Dataset.cast_column), чтобы принять столбец с путями к файлам видео и декодировать его в видео `torchcodec` с фичей [Video](/docs/datasets/v5.2.0/ru/package_reference/main_classes#datasets.Video):

```py
>>> from datasets import Dataset, Video

>>> dataset = Dataset.from_dict({"video": ["path/to/video_1", "path/to/video_2", ..., "path/to/video_n"]}).cast_column("video", Video())
>>> dataset[0]["video"]
<torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e080>
```

Если вам нужно загрузить только базовый путь к набору данных видео без декодирования объекта видео, установите `decode=False` в фиче [Video](/docs/datasets/v5.2.0/ru/package_reference/main_classes#datasets.Video):

```py
>>> dataset = dataset.cast_column("video", Video(decode=False))
>>> dataset[0]["video"]
{'bytes': None,
 'path': 'path/to/video/folder/video0.mp4'}
```

## VideoFolder

Также можно загрузить набор данных с помощью конструктора `VideoFolder`, который не требует написания собственного загрузчика данных. Это делает `VideoFolder` идеальным для быстрого создания и загрузки наборов видеоданных, содержащих несколько тысяч видео для различных задач компьютерного зрения. Структура вашего набора видеоданных должна выглядеть следующим образом:

```
folder/train/dog/golden_retriever.mp4
folder/train/dog/german_shepherd.mp4
folder/train/dog/chihuahua.mp4

folder/train/cat/maine_coon.mp4
folder/train/cat/bengal.mp4
folder/train/cat/birman.mp4
```

Если набор данных следует структуре `VideoFolder`, то его можно загрузить напрямую с помощью [load_dataset()](/docs/datasets/v5.2.0/ru/package_reference/loading_methods#datasets.load_dataset):

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_name")
>>> # OR locally:
>>> dataset = load_dataset("/path/to/folder")
```

Для локальных наборов данных это эквивалентно ручной передаче `videofolder` в [load_dataset()](/docs/datasets/v5.2.0/ru/package_reference/loading_methods#datasets.load_dataset) и директории в `data_dir`:

```py
>>> dataset = load_dataset("videofolder", data_dir="/path/to/folder")
```

Затем вы можете обращаться к видео как к объектам `torchcodec.decoders._video_decoder.VideoDecoder`:

```
>>> dataset["train"][0]
{"video": <torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e080>, "label": 0}

>>> dataset["train"][-1]
{"video": <torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e090>, "label": 1}
```

Чтобы игнорировать информацию в файле метаданных, установите `drop_metadata=True` в [load_dataset()](/docs/datasets/v5.2.0/ru/package_reference/loading_methods#datasets.load_dataset):

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_with_metadata", drop_metadata=True)
```

Если у вас нет файла метаданных, `VideoFolder` автоматически определяет имя метки по имени каталога. Если вы хотите отбросить автоматически созданные метки, установите `drop_labels=True`. В этом случае ваш набор данных будет содержать только столбец с видео:

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_without_metadata", drop_labels=True)
```

Наконец, аргумент `filters` позволяет загрузить только часть набора данных на основе условия, наложенного на метку или метаданные. Это особенно полезно, если метаданные хранятся в формате Parquet, поскольку этот формат обеспечивает быструю фильтрацию. Также рекомендуется использовать этот аргумент вместе с `streaming=True`, так как по умолчанию набор данных полностью загружается до применения фильтрации.

```python
>>> filters = [("label", "=", 0)]
>>> dataset = load_dataset("username/dataset_name", streaming=True, filters=filters)
```

> [!TIP]
> Для получения дополнительной информации о создании собственного набора данных `VideoFolder` ознакомьтесь с руководством [Создание набора данных видео](./video_dataset).

## WebDataset

Формат [WebDataset](https://github.com/webdataset/webdataset) основан на папке с TAR-архивами и подходит для больших наборов данных с видео. Из-за их размера WebDatasets, как правило, загружаются в режиме потоковой передачи (с использованием `streaming=True`).

Вы можете загрузить WebDataset следующим образом:

```python
>>> from datasets import load_dataset

>>> dataset = load_dataset("webdataset", data_dir="/path/to/folder", streaming=True)
```

## Lance

[Lance](https://lance.org) — это открытый формат таблиц для мультимодальных lakehouse-хранилищ. Таблицы Lance могут нативно хранить не только текст и скалярные значения, но и крупные бинарные объекты (blobs), такие как изображения, аудио и видео, наряду с табличными данными. Внутри таблицы Lance крупные объекты, например видео, хранятся в виде байтов со смещениями (см. [руководство по blob](https://lance.org/guide/blob/) для подробностей), что позволяет легко сканировать и фильтровать метаданные без загрузки тяжёлых видео-блобов, а затем по запросу извлекать только нужные видео-блобы.

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

```python
import lance

ds = lance.dataset("hf://datasets/lance-format/openvid-lance/data/train.lance")

# 1. Browse metadata without loading video blobs.
metadata = ds.scanner(
    columns=["caption", "aesthetic_score"],
    filter="aesthetic_score >= 4.5",
    limit=2,
).to_table().to_pylist()

# 2. Fetch a single video blob by row index.
selected_index = 0
blob_file = ds.take_blobs("video_blob", ids=[selected_index])[0]
with open("video_0.mp4", "wb") as f:
    f.write(blob_file.read())
```

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

Для получения подробной информации о работе с наборами данных Lance см. [документацию Lance](https://lance.org).

## Декодирование видео

По умолчанию, при итерации по набору данных, видео декодируются последовательно как `VideoDecoders` из torchcodec. Метаданные видео декодируются последовательно, а кадры видео не читаются, пока вы к ним не обратитесь.

Однако с помощью многопоточного декодирования можно значительно ускорить работу с набором данных:

```python
>>> import os
>>> num_threads = num_threads = min(32, (os.cpu_count() or 1) + 4)
>>> dataset = dataset.decode(num_threads=num_threads)
>>> for example in dataset:  # up to 20 times faster !
...     ...
```

Вы можете включить многопоточность с помощью `num_threads`. Это особенно полезно для ускорения потоковой передачи удалённых данных. Однако для локальных данных на быстрых дисках это может работать медленнее, чем при `num_threads=0`.

Если вас не интересуют видео, декодированные как `VideoDecoders` torchcodec, и вы хотите получить доступ к пути/байтам, вы можете отключить декодирование:

```python
>>> dataset = dataset.decode(False)
```

Примечание: [IterableDataset.decode()](/docs/datasets/v5.2.0/ru/package_reference/main_classes#datasets.IterableDataset.decode) в настоящее время доступен только для потоковых наборов данных.

