Cómo realizar cargas (en tiempo real)

Introducción

Basándonos en nuestros conocimientos básicos sobre las cargas, es hora de explorar la carga de activos en tiempo real a medida que se crean. Este enfoque permite cargar archivos durante la grabación, el renderizado o la transmisión antes de que se conozca su tamaño final.

La API de cargas en tiempo real permite que los activos se puedan reproducir en Frame.io en cuestión de segundos después de completar la grabación, lo que mejora significativamente la eficiencia del flujo de trabajo.

Vídeo de demostración

Para echar un vistazo rápido a esta funcionalidad, vea nuestra demostración en vídeo. La demostración muestra un renderizado que se carga desde Adobe Media Encoder en tiempo real, y el vídeo se puede reproducir en Frame.io tan solo 5 segundos después de que se complete el renderizado.

Requisitos previos

Si aún no lo ha hecho, revise la guía Implementar C2C: Configuración. Necesitará el access_token que se obtiene durante el proceso de autenticación y autorización. Usaremos el mismo activo de prueba de la guía básica sobre las cargas en nuestros ejemplos. Se recomienda familiarizarse con la guía básica sobre las cargas, ya que nos basaremos en esos conceptos.

Crear un activo en tiempo real

Las cargas en tiempo real comienzan con un proceso de creación de activos modificado. Al crear el activo, establezca is_realtime_upload en true y omita el parámetro filesize (o establézcalo en null), ya que el tamaño final no se conoce durante la creación:

${
>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
Especificación del punto final de la API

La documentación para /v2/devices/assets está disponible aquí.

Extensión y nombre de archivo

Los activos en tiempo real requieren una extensión de archivo. Si el nombre de archivo no se conoce al crear el activo, puede usar el campo extension en su lugar (formato: &quot;.mp4&quot;). Este enfoque es preferible cuando tiene pensado actualizar el nombre del activo más tarde.

La respuesta para activos en tiempo real es más sencilla que con la creación de activos estándar:

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

Tenga en cuenta que no se utiliza upload_urls: para las cargas en tiempo real, generaremos URL de carga bajo demanda a medida que se crea el archivo.

Solicitar URL de carga

Solicitemos una URL para la primera mitad de nuestro archivo (10 568 125 bytes), usando el asset_id de la respuesta anterior:

${
>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
Especificación del punto final de la API

La documentación para /v2/devices/assets/{asset_id}/realtime_upload/parts está disponible aquí.

Entender los parámetros de solicitud:

  • parts: Una lista de partes de carga para las que necesitamos URL. Solicitar varias URL en una sola llamada mejora la eficiencia.

number: El número de parte secuencial, empezando por 1. Los números se pueden omitir y las partes se pueden cargar en cualquier orden, pero se ensamblarán de manera secuencial. No puede haber más de 10 000 (límite de AWS). * size: Tamaño de la parte en bytes. Debe cumplir las restricciones de carga multiparte de AWS. * is_final: Indica si esta es la parte final del archivo.

La respuesta contiene las URL de carga solicitadas:

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

La lista de upload_urls corresponde directamente al orden de solicitud de parts.

Ahora cargue el primer fragmento como en la guía básica sobre las cargas:

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

A continuación, solicite una URL para la segunda y última 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

Observe estas adiciones importantes:

  • is_final se establece en true para la última parte, lo que indica que la carga se completará después de este fragmento
  • asset_filesize proporciona el tamaño total del archivo, que es necesario cuando cualquier parte tiene is_final: true

Tras recibir la URL en la respuesta:

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

Cargue el fragmento 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 @-
Gestionar la parte final

Cuando se carga la parte final, Frame.io comienza a ensamblar el archivo completo. Este proceso incluye un periodo de gracia de 60 segundos para que se complete cualquier parte restante. Recomendamos cargar la parte final solo después de que todas las demás partes se hayan cargado correctamente.

Eso es todo. Vaya a Frame.io para ver cómo su activo en tiempo real se ha cargado correctamente. 🎉

Administrar nombres de activos

Si no se conoce el nombre del archivo durante la creación del activo, puede usar el campo extension sin un 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

El sistema asignará un nombre predeterminado:

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

Puede actualizar este nombre incluyendo un campo asset_name al solicitar URL de carga:

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

El nombre solo se actualizará si el activo aún conserva su nombre predeterminado; si se ha cambiado el nombre en la interfaz de usuario de Frame.io o se ha actualizado previamente, la solicitud se ignorará.

Optimizar solicitudes de URL

Para mejorar la eficiencia, solicite URL para tantas partes como datos tenga disponibles actualmente, en lugar de hacerlo individualmente. Este enfoque es especialmente útil para archivos grandes donde la velocidad de carga podría ser más lenta que la generación de datos.

Gestionar encabezados de archivos de medios

Algunos formatos de medios requieren encabezados al principio del archivo que no se escriben hasta que el archivo completo esté terminado. Esto supone un desafío cuando el encabezado es más pequeño que el tamaño mínimo de parte de AWS de 5 MiB (5 242 880 bytes).

Nuestra recomendación:

  1. Reserve los primeros 5 242 880 bytes de datos de medios sin cargar
  2. Comience a cargar partes empezando por part_number=2
  3. Cuando el archivo esté completo, anteponga el encabezado a los datos reservados
  4. Solicite una URL para part_number=1 y cargue este fragmento combinado

Este enfoque garantiza que su primer fragmento cumpla el requisito de tamaño mínimo preservando la estructura adecuada del archivo.

Escalar el tamaño de las partes para optimizar el rendimiento

AWS impone límites que afectan a la estrategia de carga:

  • Tamaño máximo de archivo: 5 TiB (5 497 558 138 880 bytes)
  • Número máximo de partes: 10 000
  • Tamaño mínimo de parte: 5 MiB (5 242 880 bytes)

Un tamaño de parte fijo conlleva compensaciones:

  • Usar el tamaño mínimo (5 MiB) para las 10 000 partes limita el tamaño total de archivo a unos 52,4 GB
  • Distribuir uniformemente el tamaño máximo de archivo requeriría fragmentos de unos 550 MB, demasiado grandes para la transmisión eficiente de archivos más pequeños

Necesitamos una fórmula que equilibre estas restricciones, que empiece por partes pequeñas para cargas adaptables y garantice que podamos manejar archivos muy grandes si es necesario.

Fórmula recomendada para el tamaño de las partes

Este es nuestro enfoque sugerido 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

… donde part_number está entre 1 y 10_000, ambos incluidos, y format_bytes_per_second es el número promedio esperado de bytes que cree que consumirá su archivo por segundo. Veremos cómo se llegó a la fórmula más adelante.

Valor de escalar

La variable scalar y el cálculo pueden resultar un poco desconcertantes a primera vista, pero es una herramienta matemática que garantiza que sin importar qué valor usemos para format_bytes_per_second, si introducimos todos los valores part_number permitidos de 1 a 10_0000 en la función, recibiremos un conjunto de valores que suma exactamente nuestro límite de tamaño de archivo de 5 TiB, tan exactamente como sea posible. Nosotros mostramos más adelante cómo llegamos a esta fórmula.

Redondeo hacia abajo

Al usar el redondeo hacia abajo, dejamos algunos bytes sobre la mesa, pero nos aseguramos de que el redondeo estándar sobre 10 000 partes no nos haga superar accidentalmente nuestro tamaño máximo de archivo permitido. Como máximo, 10 000 bytes o 10 KB se quedarán sobre la mesa de esta manera, una compensación aceptable.

Las características importantes de esta fórmula son las siguientes:

  • Al cargar 10 000 partes, la cantidad total de datos cargados estará dentro de los 10 KB de nuestro límite de tamaño de archivo de 5 TiB.
  • Optimiza para cargas útiles más pequeñas y eficientes al principio para aumentar la capacidad de respuesta para clips cortos y de longitud media.
  • Los clips muy largos tendrán una capacidad de respuesta reducida entre el final de la escritura de un archivo y su reproducción en fotograma.

La compensación entre el segundo punto y el tercer punto se mitiga por el hecho de que la mayoría de los clips no alcanzarán el tamaño donde el tercer punto entre en juego. Intercambiamos una mayor capacidad de respuesta de la MAYORÍA de archivos por una menor capacidad de respuesta en muy pocos.

Una versión más avanzada y eficiente de nuestra fórmula (que genera una función anónima part_size_calculator con nuestro escalar estático y una velocidad de datos precomputada e integrada) podría tener este aspecto:

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

Cómo funciona la fórmula

Examinemos las características de salida de la fórmula anterior para varios tipos de archivos comunes.

Ejemplo 1: Formato web

Para formatos reproducibles en la web con una velocidad de unos 5,3 MB/s o menos (la mayoría de archivos H.264/H.265/HEVC), obtendremos una progresión del tamaño de la carga útil con este aspecto:

Total de partesBytes de carga útilMB de carga útilTotal de bytes del archivoTotal de GB del archivo
15 242 8965,2 MB5 242 8960,0 GB
100021 575 81721,6 MB10 695 361 35710,7 GB
5000413 566 329413,6 MB706 957 655 928707,0 GB
100001 638 536 6791638,5 MB5 497 558 133 9215497,6 GB
Clave de columnas de la tabla - Total de partes: El número total de partes del archivo que se cargan en AWS. - Bytes de carga útil: El tamaño de la carga útil PUT de AWS cuando part_number es igual a Total de partes. - MB de carga útil: Como Bytes de carga útil, pero en megabytes. - Total de bytes del archivo: El número total de bytes cargados para el archivo cuando se han cargado partes secuenciales para Total de partes. - Total de GB del archivo: Como Total de bytes del archivo, pero en GB.

Estos valores están bien equilibrados para cargas en tiempo real, especialmente de códecs de reproducción web como H.264; la mayoría estarán por debajo de 10,7 GB y, por tanto, se completarán en un margen de 1000 partes. El tamaño de la carga útil nunca superaría los 21,6 MB.

Si procesáramos la mitad de nuestras partes, el tamaño de la carga útil seguiría sin superar nunca los 413,5 MB. La carga alcanzaría un total de 707 GB, más que suficiente para la gran mayoría de archivos web.

Solo cuando nos acercamos al final de nuestro recuento de partes permitido, el tamaño del archivo comienza a crecer enormemente. Sin embargo, nunca supera los 1,7 GB, muy por debajo del límite de AWS de 5 GiB por parte.

Ejemplo 2: Prores 422 LT Prores 422 LT tiene una velocidad de datos de 102 Mbps y genera una tabla como esta:

Total de partesBytes de carga útilMB de carga útilTotal de bytes del archivoTotal de GB del archivo
112 750 01612,8 MB12 750 0160,0 GB
100028 857 75828,9 MB18 127 308 78318,1 GB
5000415 443 954415,4 MB735 107 948 432735,1 GB
10 0001 623 525 8171623,5 MB5 497 558 133 9585497,6 GB

Esta tabla revela propiedades útiles en comparación con nuestra fórmula optimizada para web. En las primeras 1000 partes, podemos cargar 8 GB más de archivo. Las cargas útiles iniciales más grandes significan que no necesitaremos solicitar URL demasiado rápido al principio, lo que hace que la carga sea más eficiente para la velocidad de datos más elevada. El tamaño de nuestra carga útil al final del proceso de carga sigue siendo grande.

Ejemplo 2: Camera Raw

Por último, probemos un formato Camera Raw con una velocidad de datos de 280 MB/s. Con lo rápido que llegan los datos, intentar cargar en fragmentos de 5 MiB al principio simplemente no tiene sentido:

Total de partesBytes de carga útilMB de carga útilTotal de bytes del archivoTotal de GB del archivo
1280 000 008280,0 MB280 000 0080,3 GB
1000288 091 460288,1 MB282 701 200 139282,7 GB
5000482 286 516482,3 MB1 737 245 341 5421737,2 GB
10 0001 089 146 0651089,1 MB5 497 558 133 8705497,6 GB

Las cargas útiles tempranas no solo son más eficientes, sino que ahorramos más de medio gig en la parte superior, lo que hará que esas llamadas de red sean menos susceptibles a eventos adversos de la red.

Mostrar nuestro trabajo

Antes de combinar todo en un cargador de ejemplo, veamos cómo llegamos a nuestra fórmula.

Lo que necesitábamos hacer era crear una fórmula que pasara de cargas útiles grandes y pesadas al final de nuestras partes permitidas, que la mayoría de las cargas nunca alcanzarán, a cargas útiles ligeras y eficientes cerca del principio, donde cada carga puede aprovecharlas. Al mismo tiempo, queríamos asegurarnos de que nuestro algoritmo llegue cerca del límite de tamaño de archivo de 5 TiB justo en la parte número 10 000.

Era hora de ponerse a calcular.

Queremos que nuestro gráfico crezca exponencialmente, así que nuestra fórmula probablemente debería tener un aspecto como este:

n2n^2

… donde n es el número de parte. También queremos asegurarnos de que cada parte alcance, como mínimo, la velocidad de datos para nuestra fórmula, que llamaremos r:

n2+rn^2 + r

Ahora necesitamos encontrar una fórmula que pueda decirnos la suma de esta fórmula para los primeros 10 000 números naturales (1, 2, 3, …). El símbolo sigma Σ indica una suma. Vamos a añadir esto a nuestra fórmula:

Σxn2+rΣxn^2 + r

… y redefinamos n como la serie de números naturales entre 1 y 10 000, ambos incluidos. La ecuación aún no nos es muy útil. Tiene la forma intuitiva correcta, pero si establecemos n=10 000 y r=5 242 880 como queremos, simplemente devuelve un resultado de: 385 812 135 000 (385 GB). No solo el resultado está muy por debajo de nuestro límite de tamaño de archivo de 5 TiB, sino que no hay forma de manipular la fórmula para que devuelva ese resultado.

Añadamos algo con lo que podamos trabajar:

Σxn2+rΣxn^2 + r

… donde x es un escalar que podemos resolver para obtener 5 TiB como resultado. Ahora podemos igualar la ecuación a nuestro límite de tamaño de archivo y resolver para x:

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

A menudo, las sumas deben resolverse de forma iterativa, como en un bucle for o while. Pero resulta que hay una fórmula perfecta para nosotros: una forma conocida de calcular fácilmente la suma del cuadrado de los primeros n números naturales:

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

Reorganizar en un polinomio hace que sea más fácil de ver:

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

Podemos añadir nuestras variables, x y r, a ambos lados:

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

Y finalmente establecemos nuestra nueva fórmula igual 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

Ahora solo tenemos que resolver para x estableciendo n=10 000, nuestro recuento total de partes. Esto nos dará una forma de computar un escalar estático para una velocidad de datos determinada. En lugar de hacerlo manualmente, conectémoslo a Wolfram Alpha:

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

Vamos por buen camino. Si nuestra velocidad de datos fuera el tamaño mínimo de parte (5 MiB), obtendríamos un escalar estático de:

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

En el mundo de la informática, esto representa un valor float64 de 16,33293799427617. Nuestra fórmula para determinar el tamaño de parte en esta instancia sería:

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

Donde s es el tamaño de nuestra parte.

Pero todavía tenemos un problema más. En el mundo real, no podemos tener una carga útil con bytes no enteros. Tenemos que redondear cada valor. Usaremos Python y redondearemos hacia abajo:

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

Hemos llegado a un ejemplo concreto de la función original de esta guía.

Crear un cargador básico

Echemos un vistazo a un sencillo pseudocódigo similar a Python para cargar un archivo que se está procesando en tiempo real, usando todo lo que hemos aprendido en esta guía:

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
Conceptos avanzados de cargas

El código anterior solo demuestra el flujo básico para cargar un archivo en tiempo real. En realidad, habrá que mejorar esta lógica con gestión de errores y técnicas avanzadas de carga.

Próximos pasos

Las cargas en tiempo real ofrecen una manera de hacer que su integración sea lo más adaptable posible, con activos que se pueden reproducir en Frame.io segundos después de haber terminado de grabarse. En una guía posterior se tratarán las técnicas y los requisitos avanzados de carga. Aunque se ha escrito pensando en cuestiones básicas sobre las cargas, la mayoría de la guía seguirá pudiendo aplicarse a las cargas en tiempo real.

Si aún no lo ha hecho, le recomendamos que se ponga en contacto con nuestro equipo y que luego continúe con la siguiente guía. Quedamos a la espera de tener noticias suyas.