Практическое руководство: добавление (в реальном времени)

Введение

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

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

Демонстрационное видео

Краткий обзор этой функции есть в демонстрационном видео. В видео показано добавление рендера из Adobe Media Encoder в режиме реального времени, при этом видео можно воспроизвести в Frame.io всего через 5 секунд после завершения рендеринга.

Требования

Если вы еще не сделали этого, прочитайте руководство Реализация C2C: настройка. Вам понадобится access_token, полученный в процессе аутентификации и авторизации. Мы будем использовать в наших примерах тот же тестовый ресурс из руководства по базовому добавлению. Рекомендуем ознакомиться с руководством по базовому добавлению, поскольку мы будем использовать понятия и принципы, которые там объясняются.

Создание ресурса в режиме реального времени

Добавления в режиме реального времени начинаются с создания измененного ресурса. При создании ресурса установите для параметра is_realtime_upload значение true и не указывайте параметр filesize (или установите для него значение null), поскольку окончательный размер во время создания неизвестен:

${
>curl -X POST https://api.frame.io/v2/devices/assets \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "name": "C2C_TEST_CLIP.mp4",
> "filetype": "video/mp4",
> "is_realtime_upload": true
> }
>__JSON__
>} | python -m json.tool
Спецификация конечной точки API-интерфейса

Документацию для /v2/devices/assets можно найти здесь.

Расширение и имя файла

Для ресурсов в режиме реального времени требуется расширение файла. Если при создании ресурса имя файла неизвестно, можно использовать поле extension (формат: '.mp4'). Рекомендуем этот способ, если вы планируете обновить название ресурса позже.

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

1{
2 "id": "{asset_id}",
3 "name": "C2C_TEST_CLIP.mp4"
4}

Обратите внимание, что upload_urls отсутствует — для добавлений в режиме реального времени мы будем создавать URL-адреса добавления по требованию по мере создания файла.

Запрос URL-адресов добавления

Запрашиваем URL-адрес для первой половины нашего файла (10 568 125 байт), используя asset_id из предыдущего ответа:

${
>curl -X POST https://api.frame.io/v2/devices/assets/{asset_id}/realtime_upload/parts \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "parts": [
> {
> "number": 1,
> "size": 10568125,
> "is_final": false
> }
> ]
> }
>__JSON__
>} | python -m json.tool
Спецификация конечной точки API-интерфейса

Документацию для /v2/devices/assets/{asset_id}/realtime_upload/parts можно найти здесь.

Описание параметров запроса:

  • parts: список фрагментов добавления, для которых нужны URL. Запрос нескольких URL в одном вызове повышает эффективность.

  • number: порядковый номер фрагмента, начиная с 1. Номера можно пропускать, а фрагменты добавлять в любом порядке, но собираться они будут последовательно. Не может превышать 10 000 (ограничение AWS). * size: размер фрагмента в байтах. Должен соответствовать ограничениям многочастного добавления AWS. * is_final: указывает, является ли этот фрагмент последним фрагментом файла.

Ответ содержит запрашиваемые URL добавления:

1{
2 "upload_urls": [
3 "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_01_path]"
4 ]
5}

Список upload_urls напрямую соответствует порядку запроса parts.

Теперь добавьте первый фрагмент, как описано в руководстве по базовому добавлению:

$head -c 10568125 ~/Downloads/C2C_TEST_CLIP.mp4 | \
>curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_01_path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @-

Затем запросите URL для второго и последнего фрагмента:

${
>curl -X POST https://api.frame.io/v2/devices/assets/{asset_id}/realtime_upload/parts \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "asset_filesize": 21136250,
> "parts": [
> {
> "number": 2,
> "size": 10568125,
> "is_final": true
> }
> ]
> }
>__JSON__
>} | python -m json.tool

Обратите внимание на важные дополнения:

  • для параметра is_final установлено значение true для последнего фрагмента, которое показывает, что после этого добавление будет завершено;
  • asset_filesize указывает общий размер файла. Эта информация требуется, когда любой фрагмент имеет параметр is_final: true.

После получения URL-адреса в ответе:

1{
2 "upload_urls": [
3 "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_02_path]"
4 ]
5}

Добавьте последний фрагмент:

$tail -c 10568125 ~/Downloads/C2C_TEST_CLIP.mp4 | \
>curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_02_path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @-
Обработка последнего фрагмента

Когда последний фрагмент добавлен, Frame.io начинает сборку полного файла. Этот процесс включает 60-секундный резервный период для завершения добавления любых оставшихся фрагментов. Рекомендуем добавлять последний фрагмент только после успешного добавления всех остальных фрагментов.

Вот и все! Перейдя на Frame.io, вы увидите успешно добавленный ресурс в реальном времени. 🎉

Управление именами ресурсов

Если при создании ресурса имя файла неизвестно, вы можете использовать поле расширение без имени:

${
>curl -X POST https://api.frame.io/v2/devices/assets \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "extension": ".mp4",
> "filetype": "video/mp4",
> "is_realtime_upload": true
> }
>__JSON__
>} | python -m json.tool

Система назначит имя по умолчанию:

1{
2 "id": "{asset_id}",
3 "name": "[new file].mp4"
4}

Вы можете обновить это имя, включив поле asset_name при запросе URL-адресов для добавления:

${
>curl -X POST https://api.frame.io/v2/devices/assets/{asset_id}/realtime_upload/parts \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "asset_name": "C2C_TEST_CLIP.mp4",
> "asset_filesize": 21136250,
> "parts": [
> {
> "number": 2,
> "size": 10568125,
> "is_final": true
> }
> ]
> }
>__JSON__
>} | python -m json.tool

Имя будет обновлено только в том случае, если ресурс все еще использует имя, присвоенное по умолчанию; если он был переименован в интерфейсе Frame.io или имя уже было изменено, запрос будет проигнорирован.

Оптимизация запросов URL

Для повышения эффективности запрашивайте URL-адреса для всех фрагментов, для которых у вас есть доступные данные, сразу, а не по отдельности. Это особенно важно для больших файлов, где скорость добавления может отставать от создания данных.

Обработка заголовков медиафайлов

Некоторые медиаформаты требуют заголовка в начале файла, которые записываются только после завершения всего файла. Это создает проблему, когда заголовок меньше минимального размера фрагмента AWS в 5 МиБ (5 242 880 байт).

Что мы рекомендуем:

  1. Зарезервируйте первые 5 242 880 байт медиаданных без добавления.
  2. Начинайте добавление фрагментов с part_number=2.
  3. Когда файл будет завершен, добавьте шапку к зарезервированным данным.
  4. Запросите URL для part_number=1 и добавьте этот объединенный фрагмент.

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

Масштабирование размера фрагментов для оптимизации производительности

AWS устанавливает ограничения, которые влияют на стратегию добавления:

  • максимальный размер файла: 5 ТиБ (5 497 558 138 880 байт);
  • максимальное количество фрагментов: 10 000;
  • минимальный размер фрагмента: 5 МиБ (5 242 880 байт).

Фиксированный размер фрагмента накладывает ограничения:

  • если все 10 000 фрагментов имеют минимальный размер (5 МиБ), общий размер файла будет не больше ~52,4 ГБ
  • При равномерном распределении файла максимального размера блоки будут иметь размер ~550 МБ — слишком большой для эффективной потоковой передачи файлов меньшего размера.

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

Рекомендуемая формула размера фрагмента

Вот предлагаемый подход в Python:

Python
1import math
2from typing import Callable
3
4# Constants
5MINIMUM_PART_SIZE = 5_242_880
6MAXIMUM_PART_COUNT = 10_000
7MAXIMUM_FILE_SIZE = 5_497_558_138_880
8
9# Maximum uniform data rate that allows for 10,000 parts
10MAXIMUM_DATA_RATE = MAXIMUM_FILE_SIZE // MAXIMUM_PART_COUNT
11
12def part_size(part_number: int, format_bytes_per_second: int) -> int:
13 """
14 Returns the payload size for a specific part number given the file's
15 expected data rate.
16 """
17 if part_number < 1:
18 raise ValueError("part_number must be greater than 0")
19
20 if part_number > 10_000:
21 raise ValueError("part_number must be less than 10,000")
22
23 # Make sure we never go above the maximum data rate or fall below the
24 # minimum part size, even if the data rate is lower.
25 data_rate = min(format_bytes_per_second, MAXIMUM_DATA_RATE)
26 data_rate = max(data_rate, MINIMUM_PART_SIZE)
27
28 # Calculate a scalar given our data rate. We will explain this step
29 # futher on in the guides.
30 scalar = -(2 * (125 * data_rate - 68_719_476_736)) / 8_334_583_375
31 part_size = math.floor(scalar * pow(part_number, 2)) + data_rate
32
33 return part_size

… где part_number имеет значение от 1 до 10_000 включительно, а format_bytes_per_second — это ожидаемое среднее количество байтов, которое ваш файл должен потреблять в секунду. О том, как была получена формула, — ниже.

Значение переменной scalar

Переменная scalar и расчет могут показаться немного запутанными на первый взгляд, но это математический инструмент, который гарантирует, что, независимо от значения, которое мы используем для format_bytes_per_second, если мы введем в функцию все допустимые значения part_number от 1 до 10_0000, то получим набор значений, общая сумма которых составит точно наш лимит размера файла 5 ТиБ — настолько точно, насколько это возможно. Ниже мы показываем, как мы пришли к этой формуле.

Округление до меньшего

Используя округление до меньшего, мы оставляем некоторые байты неиспользованными, но гарантируем, что обычное округление более 10 000 фрагментов не приведет случайно к превышению максимально допустимого размера файла. В худшем случае 10 000 байтов, то есть 10 КБ, останутся неиспользованными — это приемлемый компромисс.

Важные характеристики этой формулы:

  • при добавлении 10 000 фрагментов общий объем загружаемых данных будет отличаться от предельного размера файла (5 ТиБ) максимум на 10 КБ;
  • оптимизация за счет размещения меньших, более эффективных полезных нагрузок в начале для улучшения отклика при добавлении коротких и средних клипов;
  • у очень длинных клипов время между окончанием записи файла и возможностью его воспроизведения будет больше.

Недостатки третьего пункта компенсируются вторым пунктом и тем, что большинство клипов не достигнет размера, при котором третий пункт сыграет свою роль. Мы обеспечиваем быстрый отклик для БОЛЬШИНСТВА, соглашаясь на медленный отклик для очень немногих.

Более продвинутая и эффективная версия нашей формулы (которая создает анонимную функцию part_size_calculator с предварительно вычисленными и встроенными статическими скалярными значениями и скоростью данных) может выглядеть так:

Python
1def create_part_size_calculator(format_bytes_per_second: int) -> Callable[[int], int]:
2 """
3 Returns a function that takes in a `part_number` and returns a
4 `part_size` based on `data_rate`.
5 """
6
7 # Make sure we never go above the maximum data rate or fall below the
8 # minimum part size, even if the data rate is lower.
9 data_rate = min(format_bytes_per_second, MAXIMUM_DATA_RATE)
10 data_rate = max(data_rate, MINIMUM_PART_SIZE)
11
12 static_scalar = -(2 * (125 * data_rate - 68_719_476_736)) / 8_334_583_375
13
14 def part_size_calculator(part_number: int) -> int:
15 """Calculates size in bytes of upload for `part_number`."""
16 if part_number < 1:
17 raise ValueError("part_number must be greater than 0")
18
19 if part_number > 10_000:
20 raise ValueError("part_number must be less than 10,000")
21
22 return math.floor(static_scalar * pow(part_number, 2) + data_rate)
23
24 return part_size_calculator

Как работает формула.

Рассмотрим результаты вычислений, полученных с помощью приведенной выше формулы, для нескольких распространенных типов файлов.

Пример 1: веб-формат

Для форматов, воспроизводимых в веб-среде, со скоростью не более ~5,3 МБ/с (большинство файлов H.264/H.265/HEVC) мы получим следующую прогрессию размера полезной нагрузки:

Всего фрагментовБайты полезной нагрузкиМБ полезной нагрузкиВсего байт файлаВсего ГБ файла
15 242 8965,2 МБ5 242 8960,0 ГБ
100021 575 81721,6 МБ10 695 361 35710,7 ГБ
5000413 566 329413,6 МБ706 957 655 928707,0 ГБ
10 0001 638 536 6791638,5 МБ5 497 558 133 9215497,6 ГБ
Расшифровка столбцов таблицыВсего фрагментов: общее количество фрагментов файла, добавленных в AWS. — Байты полезной нагрузки: размер полезной нагрузки AWS PUT, когда значение part_number равно значению в столбце Всего фрагментов. — МБ полезной нагрузки: то же, что Байты полезной нагрузки, но в мегабайтах. — Всего байт файла: общее количество байт, добавленных для файла, когда добавлено число последовательных фрагментов, указанное в столбце Всего фрагментов. — Всего ГБ файла: то же, что Всего байт файла, но в ГБ.

Эти значения хорошо сбалансированы для добавления в режиме реального времени, особенно для кодеков веб-воспроизведения, таких как H.264; большинство будет менее 10,7 ГБ и поэтому потребует не более 1000 фрагментов. Ожидается, что размер полезной нагрузки никогда не превысит 21,6 МБ.

Если мы обработаем даже половину наших фрагментов, размер полезной нагрузки все равно никогда не превысит 413,5 МБ. Общий размер добавления составит 707 ГБ, что более чем достаточно для подавляющего большинства веб-файлов.

Только когда разрешенное количество фрагментов начинает заканчиваться, размер файла будет увеличиваться. Однако он никогда не превышает 1,7 ГБ, что значительно ниже лимита AWS в 5 ГиБ на часть.

Пример 2. Prores 422 LT Prores 422 LT имеет скорость передачи данных 102 Мбит/с и создает следующую таблицу:

Всего фрагментовБайты полезной нагрузкиМБ полезной нагрузкиВсего байт файлаВсего ГБ файла
112 750 01612,8 МБ12 750 0160,0 ГБ
100028 857 75828,9 МБ18 127 308 78318,1 ГБ
5 000415 443 954415,4 МБ735 107 948 432735,1 ГБ
10 0001 623 525 8171623,5 МБ5 497 558 133 9585497,6 ГБ

В этой таблице показаны полезные свойства по сравнению с нашей формулой, оптимизированной для веб-среды. В первых 1000 фрагментах мы можем добавить на 8 ГБ больше файлов. Большие полезные нагрузки в начале означают, что нам не нужно будет слишком быстро запрашивать URL-адреса в начале. В результате добавление идет эффективнее при более высокой скорости передачи данных. Размер полезной нагрузки в конце процесса добавления остается большим.

Пример 2. Camera Raw

Теперь попробуем формат RAW со скоростью передачи данных 280 МБ/с. При такой быстрой передаче данных попытка добавления фрагментами по 5 МиБ в начале просто не имеет смысла.

Всего фрагментовБайты полезной нагрузкиМБ полезной нагрузкиВсего байт файлаВсего ГБ файла
1280 000 008280,0 МБ280 000 0080,3 ГБ
1000288 091 460288,1 МБ282 701 200 139282,7 ГБ
5000482 286 516482,3 МБ1 737 245 341 5421737,2 ГБ
10 0001 089 146 0651089,1 МБ5 497 558 133 8705497,6 ГБ

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

Какую работу мы проделали

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

Нам нужна была формула, которая откладывала бы большие, более тяжелые полезные нагрузки на более поздние разрешенные фрагменты — до которых в большинстве добавлений дело не дойдет, — а более легкие и эффективные полезные нагрузки размещала бы в начале, где каждое добавление имеет преимущество. В то же время нужно было гарантировать, что алгоритм попадет в диапазон ограничений размера файла (5 ТиБ) точно на фрагменте номер 10 000.

На этом этапе в игру вступил математический анализ.

Чтобы график рос экспоненциально, формула должна выглядеть примерно так:

n2n^2

… где n — номер фрагмента. Кроме того, нужно, чтобы каждый фрагмент равнялся как минимум скорости передачи данных для нашей формулы, которую мы обозначим r:

n2+rn^2 + r

Теперь нам нужно найти формулу, которая может дать нам сумму этой формулы для первых 10 000 натуральных чисел (1, 2, 3, …). Символ сигма Σ обозначает суммирование. Добавим его к нашей формуле:

Σxn2+rΣxn^2 + r

… и переопределим n как ряд натуральных чисел от 1 до 10 000 включительно. Это равенство пока не слишком полезно. Интуитивно оно выглядит правильно, но, если задать n=10,000 и r=5,242,880, как нам нужно, оно просто выдает результат: 385,812,135,000 (385 ГБ). Результат не только намного ниже нашего ограничения размера файла в 5 ТиБ — нет ни одного способа изменить формулу, чтобы получить этот результат.

Попробуем ввести регулятор для настройки:

Σxn2+rΣxn^2 + r

… где x — скалярное значение, которое можно вычислить, чтобы получить 5 ТиБ в качестве результата. Теперь можно приравнять равенство к нашему ограничению размера файла и вычислить x:

Σxn2+r=5,497,558,138,880Σxn^2 + r = 5,497,558,138,880

Часто суммирование выполняется итеративно, как в цикле for или while. Но оказывается, у нас есть прекрасная формула: известный способ легко вычислить сумму квадратов первых n натуральных чисел:

Σn2=n(n+1)(2n+1)/6Σn^2 = n(n+1)(2n+1)/6

Преобразование в полином упрощает вид:

Σn2=(2n3+3n2+n)/6Σn^2 = (2n^3 + 3n^2 + n)/6

Переменные x и r можно добавить к обеим сторонам:

Σxn2+r=x(2n3+3n2+n)/6+rnΣxn^2 + r = x(2n^3 + 3n^2 + n)/6 + rn

Наконец, приравниваем нашу новую формулу к 5 ТиБ:

x(2n3+3n2+n)/6+rn=5,497,558,138,880x(2n^3 + 3n^2 + n)/6 + rn = 5,497,558,138,880

Теперь нам нужно решить ее для x, установив n=10,000 (общее количество фрагментов). Это даст возможность вычислить статический скаляр для заданной скорости передачи данных. Вместо того, чтобы решать вручную, подставим это в Wolfram Alpha:

x=(2(125r68719476736))/8334583375x = -(2 (125 r - 68719476736)) / 8334583375

Это уже кое-что! Если бы скорость передачи данных была равна минимальному размеру фрагмента (5 МиБ), мы бы получили статическое скалярное значение:

136,128,233,472/8,334,583,375136,128,233,472 / 8,334,583,375

В компьютерном мире это представляет значение float64, равное 16.33293799427617. Наша формула для определения размера фрагмента ти в этом случае будет такой:

s=16.33293799427617n2+5,242,880s = 16.33293799427617n^2 + 5,242,880

Где s — размер фрагмента.

Но остается еще одна проблема. В реальном мире не может быть полезной нагрузки с нецелыми байтами. Нам нужно округлить каждое значение. Мы будем использовать Python и округлим вниз:

Python
1math.floor(16.33293799427617 * pow(part_number, 2)) + 5_242_880

Мы пришли к конкретному примеру исходной функции, приведенной в этом руководстве.

Создание базового средства добавления

Рассмотрим простой псевдокод в стиле Python для добавления файла, отображаемого в реальном времени, используя все, что мы изучили в этом руководстве:

Python
1import math
2from datetime import datetime, timezone
3from typing import Callable
4
5# The minimum size, in bytes, for a single, non-final part upload.
6MINIMUM_PART_SIZE = 5_242_880
7# The maximum filesize in
8MAXIMUM_PART_COUNT = 10_000
9# The maximum size, in bytes, for an AWS upload.
10MAXIMUM_FILE_SIZE = 5_497_558_138_880
11
12# The data rate at which every part is an equal size, and could not
13# be any uniformly larger without violating the maximum total file
14# size if 10_000 parts were to be uploaded. it works out to
15# ~549.8 MB per payload. By enforcing this we actually never need
16# to check if a part exceeds the maximum allowed part size, as our
17# parts will never exceed ~549.8 MB.
18MAXIMUM_DATA_RATE = MAXIMUM_FILE_SIZE // MAXIMUM_PART_COUNT
19
20def create_part_size_calculator(format_bytes_per_second: int) -> Callable[[int], int]:
21 """
22 Returns a function that takes in a `part_number` and returns a
23 `part_size` based on `data_rate`.
24 """
25 ...
26
27def upload_render(data_stream: DataStream, channel: int = 0) -> None:
28 """
29 Uploads an asset for data_stream, which is a custom IO class that pulls remaining
30 upload data from an internal buffer or file, depending on how well the upload is
31 keeping pace with the render.
32
33 Uploads to `channel`
34 """
35
36 asset = c2c.asset_create(
37 extension=data_stream.extension,
38 filetype=data_stream.mimetpye,
39 channel=channel,
40 offset=datetime.now(timezone.utc) - data_stream.created_at()
41 )
42
43 calculate_part_size = create_part_size_calculator(data_stream.data_rate())
44 next_part_number = 0
45
46 while True:
47 next_payload_size = calculate_part_size(next_part_number)
48
49 # Waits until one or more chunks worth of data is ready for upload. Cache
50 # whether our data stream has completed writing the file, and the current
51 # number of bytes we have remaining to upload at this time.
52 available_bytes, stream_complete = data_stream.wait_for_available_data(
53 minimum_bytes=next_payload_size
54 )
55
56 # Build the list of parts to request based on our available data.
57 parts = []
58 while available_bytes > 0:
59 payload_size = calculate_part_size(next_part_number)
60
61 if available_bytes < payload_size and not stream_complete:
62 break
63
64 payload_size = min(payload_size, available_bytes)
65
66 parts.append(
67 c2c.RealtimeUploadPart(
68 part_number=next_part_number,
69 part_size=payload_size,
70 is_final=False
71 )
72 )
73
74 available_bytes -= payload_size
75 next_part_number += 1
76
77 # If our stream is done writing, mark the last part as final.
78 if stream_complete:
79 parts[-1].is_final = True
80
81 # Create the part URLs using the C2C endpoint.
82 response = c2c.create_realtime_parts(
83 asset_id=asset.id,
84 asset_name=None if not stream_complete else data_stream.filename,
85 asset_filesize=None if not stream_complete else data_stream.size(),
86 parts=parts
87 )
88
89 # Upload each part to its URL.
90 for part, part_url in zip(parts, response.upload_urls):
91 part_data = data_stream.read(bytes=part.size)
92 c2c.upload_chunk(part_data, part_url, data_stream.mimetype)
93
94 if stream_complete:
95 break
Расширенное добавление

Приведенный выше код демонстрирует только базовый процесс добавления файла в реальном времени. На самом деле эту логику нужно будет дополнить обработкой ошибок и способами расширенного добавления.

Далее

Добавления в реальном времени позволяют максимально сократить отклик вашей интеграции — ресурсы можно воспроизвести в Frame.io через несколько секунд после завершения записи. В другом руководстве рассматриваются способы расширенного добавления и требования к нему. Хотя оно написано для базовых добавлений, основная часть руководства применима и к добавлениям в реальном времени.

Если вы еще этого не сделали, рекомендуем связаться с нашей командой, а затем перейти к следующему руководству. Надеемся на скорую обратную связь!