Guida pratica: Caricamento (in tempo reale)

Introduzione

Partendo da quanto abbiamo detto sui caricamenti di base, adesso vediamo come caricare in tempo reale le risorse mentre vengono create. Questo approccio consente di caricare i file durante la registrazione, il rendering o lo streaming prima di conoscerne le dimensioni finali.

L’API per i caricamenti in tempo reale fa sì che le risorse diventino riproducibili in Frame.io solo pochi secondi dopo il completamento della registrazione, il che migliora notevolmente l’efficienza del flusso di lavoro.

Video dimostrativo

Per un’anteprima rapida di questa funzionalità, guarda il nostro video dimostrativo, che mostra un rendering caricato da Adobe Media Encoder in tempo reale, con il video riproducibile in Frame.io solo 5 secondi dopo il completamento del rendering.

Prerequisiti

Se non l’hai già fatto, consulta la guida Implementazione C2C: configurazione. Avrai bisogno dell’access_token ottenuto durante il processo di autenticazione e autorizzazione. Per gli esempi, useremo la stessa risorsa di test della guida sui caricamenti di base. È consigliabile conoscere bene la guida ai caricamenti di base, poiché amplieremo questi concetti.

Creazione di una risorsa in tempo reale

I caricamenti in tempo reale iniziano con un processo diverso di creazione delle risorse. Durante la creazione della risorsa, imposta is_realtime_upload su true e ometti il parametro filesize (oppure impostalo su null), poiché la dimensione finale non è nota durante la creazione:

${
>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
Specifica dell'endpoint API

La documentazione per /v2/devices/assets è disponibile qui.

Estensione e nome file

Le risorse in tempo reale richiedono un’estensione file. Se il nome file non è noto durante la creazione della risorsa, puoi usare il campo extension (formato: '.mp4'). Questo approccio è preferibile se prevedi di aggiornare il nome della risorsa in seguito.

La risposta per le risorse in tempo reale è semplificata rispetto alla creazione delle risorse standard:

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

Nota che upload_urls è assente: per i caricamenti in tempo reale, genereremo degli URL di caricamento on-demand durante la creazione del file.

Richiesta di un URL di caricamento

Richiediamo un URL per la prima metà del nostro file (10.568.125 byte), usando l’asset_id della risposta precedente:

${
>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
Specifica dell'endpoint API

La documentazione per /v2/devices/assets/{asset_id}/realtime_upload/parts è disponibile qui.

Informazioni sui parametri della richiesta:

  • parts: un elenco di parti di caricamento per cui sono necessari gli URL. Richiedi più URL in una singola chiamata per migliorare l’efficienza.

  • number: il numero di parte sequenziale, a partire da 1. I numeri possono essere saltati e le parti possono essere caricate in qualsiasi ordine, ma vengono assemblate in sequenza. Non può superare 10.000 (limite AWS). * size: dimensione della parte in byte. Deve rispettare le restrizioni di caricamento multi-parte di AWS. * is_final: indica se questa è la parte finale del file.

La risposta contiene gli URL di caricamento richiesti:

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

L’elenco di upload_url corrisponde direttamente all’ordine della richiesta parts.

Adesso carica il primo chunk come indicato nella guida al caricamento di 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 @-

Poi richiedi un URL per la seconda e ultima parte:

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

Prendi nota di queste aggiunte importanti:

  • is_final è impostato su true per l’ultima parte, a indicare che il caricamento sarà completo dopo questo chunk
  • asset_filesize fornisce la dimensione totale del file, richiesta quando is_final: true per qualsiasi parte

Dopo aver ricevuto l’URL nella risposta:

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

Carica il chunk finale:

$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 @-
Gestione della parte finale

Quando viene caricata la parte finale, Frame.io inizia ad assemblare il file completo. Questo processo include un periodo di tolleranza di 60 secondi per il completamento delle parti rimanenti. Consigliamo di caricare la parte finale solo dopo aver caricato tutte le altre parti.

Ecco fatto! Vai su Frame.io per visualizzare la risorsa in tempo reale caricata. 🎉

Gestione dei nomi delle risorse

Se il nome del file non è noto durante la creazione della risorsa, puoi usare il campo extension senza specificare un nome (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

Il sistema assegnerà un nome predefinito:

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

Puoi aggiornare questo nome includendo un campo asset_name quando richiedi gli URL di caricamento:

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

Il nome si aggiornerà solo se la risorsa ha ancora il nome predefinito; la richiesta verrà ignorata se è stata rinominata nell’interfaccia Frame.io o se è stata aggiornata in precedenza.

Ottimizzazione delle richieste URL

Per efficienza, richiedi gli URL per tutte le parti per cui disponi attualmente di dati, piuttosto che individualmente. Questo approccio è particolarmente utile per file di grandi dimensioni dove la velocità di caricamento potrebbe essere inferiore alla generazione dei dati.

Gestione delle intestazioni dei file media

Alcuni formati media richiedono intestazioni all’inizio del file che non vengono scritte finché l’intero file non viene completato. Questo crea una problema quando l’intestazione è più piccola della dimensione minima delle parti di AWS di 5 MiB (5.242.880 byte).

Consigliamo quanto segue:

  1. Riserva i primi 5.242.880 byte di dati del media senza caricarli
  2. Inizia a caricare le parti iniziando con part_number=2
  3. Quando il file è completo, anteponi l’intestazione ai dati riservati
  4. Richiedi un URL per part_number=1 e carica questo chunk combinato

Questo approccio assicura che il primo chunk rispetti il requisito della dimensione minima, preservando la struttura corretta del file.

Scalare la dimensione delle parti per prestazioni ottimali

AWS impone dei limiti che influenzano la strategia di caricamento:

  • Dimensione massima del file: 5 TiB (5.497.558.138.880 byte)
  • Numero massimo di parti: 10.000
  • Dimensione minima delle parti: 5 MiB (5.242.880 byte)

Una dimensione fissa delle parti crea alcuni compromessi:

  • L’uso della dimensione minima (5 MiB) per tutte le 10.000 parti limita la dimensione totale del file a circa 52,4 GB
  • Distribuire uniformemente la dimensione massima del file richiederebbe chunk di circa 550 MB, troppo grandi per lo streaming efficiente di file più piccoli

Serve una formula che bilanci questi vincoli, iniziando con parti piccole per caricamenti dinamici e garantendo al contempo di poter gestire file molto grandi se necessario.

Formula consigliata per la dimensione delle parti

Ecco il nostro approccio suggerito in 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

… dove part_number è compreso tra 1 e 10_000 incluso, mentre format_bytes_per_second è il numero medio previsto di byte che il file dovrebbe consumare per secondo. Più avanti spieghiamo come abbiamo calcolato questa formula.

Valore scalare

La variabile scalar e il calcolo potrebbero risultare un po’ confusi a prima vista, ma si tratta di uno strumento matematico che garantisce che, indipendentemente dal valore usato per format_bytes_per_second, se inseriamo tutti i valori part_number consentiti da 1 a 10_0000 nella funzione, riceveremo un insieme di valori che restituisce esattamente il limite di dimensione file di 5 TiB (ovviamente nel modo più esatto possibile). Più avanti spiegheremo i nostri calcoli per arrivare a questa formula.

Arrotondamento per difetto

Usando l’arrotondamento per difetto, alcuni byte non verranno utilizzati, ma garantiamo che l’arrotondamento normale oltre 10.000 parti non ci faccia superare accidentalmente la dimensione massima consentita del file. Al massimo, verranno lasciati inutilizzati 10.000 byte (o 10 KB), il che è un compromesso accettabile.

Ecco le caratteristiche importanti di questa formula:

  • Quando carichi 10.000 parti, la quantità totale di dati caricati sarà entro 10 KB del nostro limite di dimensione file di 5 TiB.
  • L’operazione è ottimizzata per payload più piccoli ed efficienti all’inizio, in modo da aumentare la reattività per clip di durata medio-breve.
  • Le clip molto lunghe avranno una reattività ridotta tra la fine della scrittura di un file e il momento in cui diventa riproducibile nel fotogramma.

Il compromesso tra il secondo e il terzo punto è mitigato dal fatto che la maggior parte delle clip non raggiungerà la dimensione in cui entra in gioco il terzo punto. Stiamo scambiando una maggiore reattività della MAGGIOR PARTE dei file con una minore reattività di pochissimi file.

Una versione più avanzata ed efficiente della nostra formula (che genera una funzione anonima part_size_calculator in cui sono precalcolati e incorporati il valore scalare statico e la velocità di trasmissione dei dati) potrebbe essere simile a questa:

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

Come funziona la formula.

Analizziamo le caratteristiche di output della formula in alto per vari tipi di file comuni.

Esempio 1: formato web

Per i formati riproducibili sul web con una velocità di circa 5,3 MB/s o inferiore (la maggior parte dei file H.264/H.265/HEVC), otterremo una progressione della dimensione del payload simile a questa:

Parti totaliByte del payloadMB del payloadByte totali del fileGB totali del file
15.242.8965,2 MB5.242.8960,0 GB
1.00021.575.81721,6 MB10.695.361.35710,7 GB
5.000413.566.329413,6 MB706.957.655.928707,0 GB
10.0001.638.536.6791.638,5 MB5.497.558.133.9215.497,6 GB
Legenda delle colonne della tabella - Parti totali: il numero totale di parti del file caricate su AWS. - Byte del payload: la dimensione del payload AWS PUT quando part_number è uguale a Parti totali. - MB del payload: come Byte del payload, ma in megabyte. - Byte totali del file: il numero totale di byte caricati per il file quando sono state caricate parti sequenziali per Parti totali. - GB totali del file: come Byte totali del file, ma in GB.

Questi valori sono ben bilanciati per i caricamenti in tempo reale, specialmente per codec di riproduzione web come H.264; la maggior parte sarà sotto i 10,7 GB e, perciò, sarà completa entro 1.000 parti. La dimensione del payload non supererebbe mai i 21,6 MB.

Se elaborassimo metà delle nostre parti, la dimensione del payload non supererebbe comunque mai i 413,5 MB. Il caricamento raggiungerebbe un totale di 707 GB, più che sufficiente per la stragrande maggioranza dei file web.

È solo quando ci avviciniamo alla fine del numero di parti consentite che la dimensione del file inizia a crescere molto. Tuttavia, non supera mai 1,7 GB, ben al di sotto del limite AWS di 5 GiB per parte.

Esempio 2: Prores 422 LT. Prores 422 LT ha una velocità dati di 102 Mbps e genera una tabella come questa:

Parti totaliByte del payloadMB del payloadByte totali del fileGB totali del file
112.750.01612,8 MB12.750.0160,0 GB
1.00028.857.75828,9 MB18.127.308.78318,1 GB
5.000415.443.954415,4 MB735.107.948.432735,1 GB
10.0001.623.525.8171.623,5 MB5.497.558.133.9585.497,6 GB

Questa tabella mostra delle proprietà utili rispetto alla formula ottimizzata per il web. Nelle prime 1.000 parti possiamo caricare 8 GB in più di file. I payload iniziali più grandi significano che non sarà necessario richiedere URL troppo rapidamente all’inizio, rendendo il caricamento più efficiente per la velocità di dati più elevata. La dimensione del payload verso la fine del processo di caricamento rimane elevata.

Esempio 2: Camera Raw

Infine, proviamo un formato Camera RAW che ha una velocità di dati di 280 MB/s. Con dati che arrivano così velocemente, provare a caricare in chunk da 5 MiB all’inizio semplicemente non ha senso:

Parti totaliByte del payloadMB del payloadByte totali del fileGB totali del file
1280.000.008280,0 MB280.000.0080,3 GB
1.000288.091.460288,1 MB282.701.200.139282,7 GB
5.000482.286.516482,3 MB1.737.245.341.5421.737,2 GB
10.0001.089.146.0651.089,1 MB5.497.558.133.8705.497,6 GB

I payload iniziali non sono solo più efficienti, ma stiamo risparmiando oltre mezzo gigabyte nella fascia superiore, rendendo le chiamate di rete meno suscettibili a eventi di rete avversi.

Mostrare il lavoro svolto

Prima di unire tutto in un esempio di uploader, vediamo come siamo arrivati alla nostra formula.

Dovevamo elaborare una formula che scambiasse payload grandi e pesanti alla fine delle parti consentite (che la maggior parte dei caricamenti non raggiungerà mai) con payload leggeri ed efficienti all’inizio, in cui ogni caricamento può trarne vantaggio. Allo stesso tempo, volevamo assicurarci che il nostro algoritmo arrivasse nell’ordine di grandezza del limite di 5 TiB proprio al numero di parte 10.000.

È qui che entra in gioco il calcolo infinitesimale.

Vogliamo che il grafo cresca esponenzialmente, quindi la formula dovrebbe probabilmente assomigliare a quanto segue:

n2n^2

… dove n è il numero della parte. Vogliamo anche assicurarci che ogni parte corrisponda, come minimo, alla velocità di trasferimento dei dati per la nostra formula, che chiameremo r:

n2+rn^2 + r

Ora dobbiamo trovare una formula che ci dica la somma di questa formula per i primi 10.000 numeri naturali (1, 2, 3 …). Il simbolo sigma Σ indica la somma. Aggiungiamolo alla nostra formula:

Σxn2+rΣxn^2 + r

… e ridefiniamo n come la serie di numeri naturali tra 1 e 10.000 (incluso). L’equazione non ci è ancora molto utile. Ha la forma intuitiva giusta, ma se impostiamo n=10.000 e r=5.242.880 come vogliamo, otteniamo semplicemente un risultato: 385.812.135.000 (385 GB). Il risultato non è solo molto al di sotto del nostro limite di dimensione file di 5 TiB, ma non c’è modo di manipolare la formula per ottenere quel risultato.

Vediamo di perfezionare la formula:

Σxn2+rΣxn^2 + r

… dove x è un valore scalare che possiamo risolvere per ottenere 5 TiB come risultato. Ora possiamo impostare l’equazione in modo che sia uguale al nostro limite di dimensione file e risolvere per x:

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

Spesso, le somme devono essere risolte in modo iterativo, come in un loop for o while. In realtà, esiste una formula perfetta per il nostro caso: un modo noto per calcolare a basso costo la somma del quadrato per i primi n numeri naturali:

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

Basta riorganizzarla in un polinomio per renderla più facile da osservare:

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

Possiamo aggiungere le nostre variabili, x e r, su entrambi i lati:

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

E infine impostiamo la nostra nuova formula uguale a 5 TiB:

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

Ora tutto quello che dobbiamo fare è risolvere per x impostando n=10.000, ovvero il conteggio totale delle parti. Questo ci darà un modo per calcolare un valore scalare statico per una determinata velocità di trasferimento dei dati. Invece di farlo a mano inseriamolo in Wolfram Alpha:

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

Ora sì che stiamo ottenendo dei risultati! Se la velocità di trasferimento dei dati fosse la dimensione minima della parte (5 MiB), otterremmo un valore scalare statico pari a:

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

Nell’ambito informatico, questo rappresenta un valore float64 di 16,33293799427617. La nostra formula per determinare la dimensione della parte in questa Istanza sarebbe:

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

dove s è la dimensione della nostra parte.

Abbiamo ancora un altro problema. Nel mondo reale, non possiamo avere un payload con byte non interi. Dobbiamo arrotondare ogni valore. Useremo Python e eseguiremo l’arrotondamento per difetto:

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

Siamo arrivati a un esempio concreto della funzione originale fornita in questa guida.

Creazione di un uploader di base

Diamo un’occhiata ad un semplice pseudocodice simile a Python per caricare un file che viene sottoposto a rendering in tempo reale, utilizzando tutto quello che abbiamo imparato in questa guida:

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
Caricamento avanzato

Il codice precedente mostra solo il flusso di base per caricare un file in tempo reale. In realtà, questa logica deve essere migliorata con la gestione degli errori e tecniche di caricamento avanzato.

Avanti

I caricamenti in tempo reale sono un modo per rendere l’integrazione più dinamica possibile, con le risorse che diventano riproducibili in Frame.io pochi secondi dopo essere state registrate. In una guida successiva si parlerà delle tecniche e dei requisiti avanzati di caricamento. Anche se è scritta pensando ai caricamenti di base, la maggior parte della guida sarà comunque applicabile ai caricamenti in tempo reale.

Se non l’hai già fatto, ti incoraggiamo a contattare il nostro team, poi continua con la prossima guida. A presto!