Comment effectuer un chargement (en temps réel)

Présentation

En nous appuyant sur nos connaissances de base sur le chargement, explorons le chargement de ressources en temps réel pendant leur création. Cette approche permet de charger des fichiers pendant l’enregistrement, le rendu ou le streaming avant de connaître leur taille finale.

L’API de chargements en temps réel permet aux ressources d’être lisibles dans Frame.io quelques secondes seulement après la fin de l’enregistrement, ce qui améliore considérablement l’efficacité du workflow.

Vidéo de démonstration

Pour un aperçu rapide de cette fonctionnalité, regardez notre vidéo de démonstration. La vidéo de démonstration montre le chargement d’un rendu depuis Adobe Media Encoder en temps réel, la vidéo étant lisible dans Frame.io seulement 5 secondes après la fin du rendu.

Conditions préalables

Si vous ne l’avez pas encore fait, consultez le guide Implémentation C2C : configuration. Vous aurez besoin de l’élément access_token obtenu au cours du processus d’authentification et d’autorisation. Nous utiliserons la même ressource de test que dans le guide de chargement de base pour nos exemples. Une connaissance du guide de chargement de base est recommandée, car nous nous appuierons sur ces concepts.

Création d’une ressource en temps réel

Les chargements en temps réel commencent par un processus de création de ressource modifié. Lors de la création de la ressource, définissez is_realtime_upload sur vrai et omettez le paramètre filesize (ou définissez-le sur null), car la taille finale n’est pas connue lors de la création :

${
>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
Spécification de point d’entrée de l’API

Rendez-vous sur cette page pour consulter la documentation /v2/devices/assets.

Extension et nom de fichier

Les ressources en temps réel nécessitent une extension de fichier. Si le nom de fichier n’est pas connu lors de la création de la ressource, vous pouvez utiliser le champ extension à la place (format : ’.mp4’). Cette approche est préférable lorsque vous prévoyez de mettre à jour le nom de la ressource plus tard.

La réponse pour les ressources en temps réel est simplifiée par rapport à la création de ressource standard :

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

Notez que upload_urls est absent. Pour les chargements en temps réel, nous générerons les URL de chargement à la demande pendant la création du fichier.

Demande d’URL de chargement

Demandez une URL pour la première moitié du fichier (10 568 125 octets), en utilisant le paramètre asset_id de la réponse précédente :

${
>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
Spécification de point d’entrée de l’API

Rendez-vous sur cette page pour consulter la documentation /v2/devices/assets/{asset_id}/realtime_upload/parts.

Comprendre les paramètres de requête :

  • parts : une liste des parties de chargement pour lesquelles nous avons besoin d’URL. Demandez plusieurs adresses URL au sein d’un appel unique pour améliorer l’efficacité.

  • number : le numéro de partie séquentiel, commençant à 1. Les numéros peuvent être ignorés et les parties chargées dans n’importe quel ordre, mais elles seront assemblées de manière séquentielle. Ne peut pas dépasser 10 000 (limite AWS). * size : taille de la partie en octets. Doit respecter les restrictions de chargement multi-parties AWS. * is_final : indique s’il s’agit de la partie finale du fichier.

La réponse contient les URL de chargement demandées :

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

La liste upload_urls correspond directement à l’ordre de la requête parts.

Chargez maintenant le premier bloc comme dans le guide de chargement de base :

$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 @-

Demandez ensuite une URL pour la deuxième et dernière partie :

${
>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

Notez ces ajouts importants :

  • is_final est défini sur vrai pour la dernière partie, signalant que le chargement se terminera après ce bloc.
  • asset_filesize fournit la taille totale du fichier, qui est requise lorsqu’une partie inclut le paramètre is_final: true.

Après avoir reçu l’URL dans la réponse :

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

Chargez le bloc final :

$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 @-
Gestion de la partie finale

Lorsque la partie finale est chargée, Frame.io commence à assembler le fichier complet. Ce processus inclut un délai de grâce de 60 secondes pour que toutes les parties restantes se terminent. Nous recommandons de charger la partie finale seulement après que toutes les autres parties ont été chargées avec succès.

Et voilà ! Accédez à Frame.io pour voir votre ressource en temps réel chargée avec succès. 🎉

Gestion des noms de ressource

Si le nom du fichier n’est pas connu lors de la création de la ressource, vous pouvez utiliser le champ extension sans paramètre name :

${
>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

Le système attribue un nom par défaut :

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

Vous pouvez mettre à jour ce nom en incluant un champ asset_name lors de la demande d’URL de chargement :

${
>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

Le nom ne se met à jour que si la ressource conserve encore son nom par défaut ; si elle a été renommée dans l’interface utilisateur Frame.io ou mise à jour précédemment, la demande est ignorée.

Optimisation des demandes d’URL

Pour plus d’efficacité, demandez des URL pour autant de parties que vous avez actuellement de données disponibles, plutôt qu’individuellement. Cette approche est particulièrement utile pour les gros fichiers où la vitesse de chargement peut avoir du mal à suivre le rythme de la génération de données.

Gestion des en-têtes de fichiers multimédias

Certains formats multimédias nécessitent des en-têtes au début du fichier, qui ne sont pas écrits tant que le fichier entier n’est pas terminé. Cela devient problématique lorsque l’en-tête est plus petit que la taille de partie minimale d’AWS de 5 Mio (5 242 880 octets).

Notre recommandation est la suivante :

  1. Réservez les 5 242 880 premiers octets de données multimédias sans les charger.
  2. Commencez à charger des parties en commençant par part_number=2.
  3. Lorsque le fichier est terminé, ajoutez l’en-tête aux données réservées.
  4. Demandez une URL pour part_number=1 et chargez ce bloc combiné.

Cette approche garantit que votre premier bloc respecte l’exigence de taille minimale tout en préservant la structure appropriée du fichier.

Adapter la taille des parties pour des performances optimales

AWS impose des limites qui affectent la stratégie de chargement :

  • Taille de fichier maximale : 5 Tio (5 497 558 138 880 octets)
  • Nombre maximal de parties : 10 000
  • Taille de partie minimale : 5 Mio (5 242 880 octets)

Une taille de partie fixe crée des compromis :

  • L’utilisation de la taille minimale (5 Mio) pour les 10 000 parties limite la taille totale du fichier à environ 52,4 Go.
  • Répartir uniformément la taille maximale de fichier nécessiterait des blocs d’environ 550 Mo, ce qui est trop volumineux pour un flux efficace de fichiers plus petits.

Nous avons besoin d’une formule qui équilibre ces contraintes, en commençant par de petites parties pour des chargements réactifs tout en nous assurant de pouvoir gérer de très gros fichiers si nécessaire.

Formule de taille de partie recommandée

Voici notre approche suggérée en 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

… où part_number est compris entre 1 et 10_000, inclusivement et où format_bytes_per_second est le nombre moyen d’octets que votre fichier devrait consommer par seconde. Nous verrons plus loin comment nous sommes parvenus à cette formule.

Valeur scalaire

La variable scalar et le calcul peuvent sembler un peu déroutants au premier abord, mais il s’agit d’un outil mathématique qui garantit que peu importe la valeur que nous utilisons pour format_bytes_per_second, si nous alimentons toutes les valeurs part_number autorisées de 1 à 10_0000 dans la fonction, nous recevrons un ensemble de valeurs qui totalise exactement notre limite de taille de fichier de 5 Tio (aussi exactement que possible). Nous expliquons plus loin comment nous sommes arrivés à cette formule.

Arrondi à l’inférieur

En utilisant l’arrondi à l’inférieur, nous laissons quelques octets de côté, mais nous nous assurons que l’arrondi régulier sur 10 000 parties ne nous fait pas accidentellement dépasser notre taille de fichier maximale autorisée. Au maximum, 10 000 octets (ou 10 Ko) seront laissés de côté de cette façon, un compromis acceptable.

Les caractéristiques importantes de cette formule sont les suivantes :

  • Lors du chargement de 10 000 parties, la quantité totale de données chargées sera à 10 Ko près notre limite de taille de fichier de 5 Tio.
  • Cela permet d’obtenir des payloads plus petites et plus efficaces au début pour augmenter la réactivité des clips courts et de longueur moyenne.
  • Les clips très longs auront une réactivité réduite entre la fin de l’écriture d’un fichier et le moment où il devient lisible dans un cadre.

Le compromis entre le deuxième et le troisième point est atténué par le fait que la plupart des clips n’atteindront pas une taille nécessitant l’utilisation du troisième point. Nous échangeons une réactivité accrue de la PLUPART des fichiers contre une réactivité diminuée de très peu.

Une version plus avancée et efficace de notre formule (qui génère une fonction part_size_calculator anonyme avec notre scalaire statique et le débit de données précalculés et intégrés) pourrait ressembler à ceci :

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

Performances de la formule.

Examinons les caractéristiques de sortie de la formule ci-dessus sur plusieurs types de fichiers courants.

Exemple 1 : format web

Pour les formats lisibles sur le Web avec un débit d’environ 5,3 Mo/s ou moins (la plupart des fichiers H.264/H.265/HEVC), nous obtiendrons une progression de la taille de payload qui ressemble à ceci :

Nombre total de partiesOctets de payloadMo de payloadTaille totale du fichier (octets)Taille totale du fichier (Go)
15,242,8965,2 Mo5,242,8960,0 Go
1,00021,575,81721,6 Mo10,695,361,35710,7 Go
5,000413,566,329413,6 Mo706,957,655,928707,0 Go
10 0001 638 536 6791 638,5 Mo5,497,558,133,9215 497,6 Go
Clé des colonnes du tableau - Nombre total de parties : le nombre total de parties de fichier chargées sur AWS. - Octets de payload : la taille du payload PUT AWS lorsque part_number est égal à Nombre total de parties. - Mo de payload : comme Octets de payload, mais en mégaoctets. - Taille totale du fichier (octets) : le nombre total d’octets chargés pour le fichier lorsque les parties séquentielles Nombre total de parties ont été chargées. - Taille totale du fichier (Go) : comme Taille totale du fichier (octets), mais en Go.

Ces valeurs sont parfaitement équilibrées pour les chargements en temps réel, en particulier pour les codecs de lecture web comme H.264 ; la plupart seront inférieurs à 10,7 Go et seront donc terminés dans les 1 000 parties. La taille de payload ne dépasserait jamais 21,6 Mo.

Si nous traitions la moitié de nos parties, la taille du payload ne dépasserait jamais 413,5 Mo. Le chargement totaliserait 707 Go, ce qui est largement suffisant pour la grande majorité des fichiers web.

Ce n’est qu’une fois que nous approchons de la fin de notre nombre de parties autorisé que la taille du fichier commence à augmenter drastiquement. Cependant, elle ne dépasse jamais 1,7 Go, ce qui est bien en dessous de la limite AWS de 5 Gio par partie.

Exemple 2 : Prores 422 LT Prores 422 LT a un débit de données de 102 Mbit/s et génère un tableau comme suit :

Nombre total de partiesOctets de payloadMo de payloadTaille totale du fichier (octets)Taille totale du fichier (Go)
112,750,01612,8 Mo12,750,0160,0 Go
1,00028,857,75828,9 Mo18,127,308,78318,1 Go
5,000415,443,954415,4 Mo735,107,948,432735,1 Go
10,0001,623,525,8171 623,5 Mo5,497,558,133,9585 497,6 Go

Ce tableau révèle des propriétés utiles par rapport à notre formule optimisée pour le Web. Dans les 1 000 premières parties, nous pouvons charger 8 Go de fichier en plus. Des payloads initiaux plus importantes signifient que nous n’aurons pas besoin de demander des URL trop rapidement au début, ce qui rend le chargement plus efficace pour le débit de données plus élevé. La taille de notre payload à la fin du processus de chargement reste importante.

Exemple 2 : Camera Raw

Essayons enfin un format Camera RAW dont le débit de données est de 280 Mo/s. Avec des données arrivant si rapidement, essayer de charger par blocs de 5 Mo au début n’a tout simplement pas de sens :

Nombre total de partiesOctets de payloadMo de payloadTaille totale du fichier (octets)Taille totale du fichier (Go)
1280,000,008280,0 Mo280,000,0080,3 Go
1,000288,091,460288,1 Mo282,701,200,139282,7 Go
5,000482,286,516482,3 Mo1,737,245,341,5421 737,2 Go
10,0001,089,146,0651 089,1 Mo5,497,558,133,8705 497,6 Go

Non seulement les payloads précoces sont plus efficaces, mais nous économisons plus d’un demi-gigaoctet à la limite supérieure, ce qui rendra ces appels réseau moins sensibles aux événements réseau défavorables.

Présentation de notre travail

Avant de rassembler notre travail dans un exemple de système de chargement, voyons comment nous sommes arrivés à notre formule.

Nous devions concevoir une formule qui remplaçait des payloads importants et lourds à la fin de nos parties autorisées (que la plupart des chargements n’atteindront jamais) par des payloads légers et efficaces près du début, où chaque chargement peut en tirer parti. En même temps, nous voulions nous assurer que notre algorithme atteindrait approximativement la limite de taille de fichier de 5 Tio exactement au numéro de partie 10 000.

Il était indispensable d’effectuer des calculs.

Nous voulons que notre graphe présente une croissance exponentielle. Notre formule devrait donc probablement ressembler à ceci :

n2n^2

… où n est le numéro de partie. Nous voulons également nous assurer que chaque partie représente, au minimum, le taux de données de notre formule, que nous appellerons r :

n2+rn^2 + r

Maintenant, nous devons trouver une formule qui peut nous indiquer la somme de cette formule pour les 10 000 premiers nombres naturels (1, 2, 3, …). Le symbole sigma Σ désigne la somme. Ajoutons-le à notre formule :

Σxn2+rΣxn^2 + r

…et redéfinissons n comme la série des nombres naturels compris entre 1 et 10 000, inclus. Cette équation ne nous est pas encore très utile. Sa forme intuitive est bonne, mais si nous définissons n=10 000 et r=5 242 880 comme nous le voulons, elle produit simplement un résultat : 385 812 135 000 (385 Go). Non seulement le résultat est largement inférieur à notre limite de taille de fichier de 5 Tio, mais il n’y a aucun moyen de manipuler la formule pour produire ce résultat.

Ajoutons donc un paramètre d’ajustement :

Σxn2+rΣxn^2 + r

… où x est un scalaire que nous pouvons résoudre pour obtenir 5 Tio comme résultat. Maintenant, nous pouvons définir l’équation pour qu’elle soit égale à notre limite de taille de fichier et la résoudre pour x :

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

Souvent, les sommes doivent être résolues de façon itérative, comme dans une boucle for ou while. Mais il s’avère qu’il existe une formule parfaite pour nous : un moyen connu de calculer de manière économique la somme des carrés pour les n premiers nombres naturels :

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

En la reformulant sous forme de polynôme, tout devient plus clair :

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

Nous pouvons ajouter nos variables, x et r, des deux côtés :

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

Et enfin, nous définissons notre nouvelle formule égale à 5 Tio :

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

Il ne nous reste plus qu’à résoudre x en définissant n=10 000, notre nombre total de parties. Cela nous donnera un moyen de calculer un scalaire statique pour un débit de données donné. Plutôt que de le faire à la main, saisissons-le dans Wolfram Alpha :

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

Nous sommes sur le point d’arriver à un résultat ! Si notre débit de données était la taille minimale de partie (5 Mio), nous obtiendrions un scalaire statique de :

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

En informatique, cela représente une valeur float64 de 16,33293799427617. Notre formule pour déterminer la taille de partie dans cette instance serait :

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

s est notre taille de partie.

Nous avons encore un problème. Dans le monde réel, nous ne pouvons pas avoir une payload avec des octets non entiers. Nous devons arrondir chaque valeur. Nous allons utiliser Python pour arrondir vers le bas :

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

Nous sommes arrivés à un exemple concret de la fonction originale présentée dans ce guide.

Création d’un outil de chargement de base

Examinons du pseudocode simple de type Python pour charger un fichier rendu en temps réel, en utilisant tout ce que nous avons appris dans ce guide :

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
Chargement avancé

Le code ci-dessus ne démontre que le flux de base du chargement d’un fichier en temps réel. En réalité, cette logique devra être améliorée avec la gestion des erreurs et les techniques de chargement avancé.

Étapes suivantes

Les chargements en temps réel offrent un moyen de rendre votre intégration aussi réactive que possible, avec des ressources qui deviennent lisibles dans Frame.io quelques secondes après la fin de l’enregistrement. Dans un prochain guide, nous aborderons les techniques et exigences relatives aux chargements avancés. Bien qu’il soit écrit en pensant aux chargements de base, la majorité du guide s’applique également aux chargements en temps réel.

Si ce n’est pas déjà fait, nous vous encourageons à contacter notre équipe, puis à passer au guide suivant. Nous nous ferons un plaisir de répondre à vos questions.