> This page is for De cámara a la nube.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# 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](https://f.io/qjwfGmTa). 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](./implementing-c2c-setting-up). Necesitará el `access_token` que se obtiene durante el [proceso de autenticación y autorización](./implementing-c2c-authentication-and-authorization). Usaremos el mismo [activo de prueba](https://f.io/Rq1q5CzB) de la guía básica sobre las cargas en nuestros ejemplos. Se recomienda familiarizarse con la [guía básica sobre las cargas](./how-to-basic-upload), 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:

```shell
{
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
```




<Info title="Especificación del punto final de la API">
  La documentación para `/v2/devices/assets` está disponible [aquí](/camera-to-cloud/api-reference/device-asset-create).
</Info>

<Warning title="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.
</Warning>


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





```json
{
    "id": "{asset_id}",
    "name": "C2C_TEST_CLIP.mp4"
}
```

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:

```shell
{
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
```




<Info title="Especificación del punto final de la API">
  La documentación para `/v2/devices/assets/{asset_id}/realtime_upload/parts` está disponible [aquí](/camera-to-cloud/api-reference/device-create-realtime-upload-parts).
</Info>


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](https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html). * `is_final`: Indica si esta es la parte final del archivo.

La respuesta contiene las URL de carga solicitadas:





```json
{
    "upload_urls": [
        "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_01_path]"
    ]
}
```

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:





```shell
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:





```shell
{
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:





```json
{
    "upload_urls": [
        "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_02_path]"
    ]
}
```





Cargue el fragmento final:





```shell
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 @-
```




<Warning title="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.



</Warning>


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`:

```shell
{
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:





```json
{
    "id": "{asset_id}",
    "name": "[new file].mp4"
}
```

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

```shell
{
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`**

```python title="Python"
import math
from typing import Callable

# Constants
MINIMUM_PART_SIZE = 5_242_880
MAXIMUM_PART_COUNT = 10_000
MAXIMUM_FILE_SIZE = 5_497_558_138_880

# Maximum uniform data rate that allows for 10,000 parts
MAXIMUM_DATA_RATE = MAXIMUM_FILE_SIZE // MAXIMUM_PART_COUNT

def part_size(part_number: int, format_bytes_per_second: int) -> int:
    """
    Returns the payload size for a specific part number given the file's
    expected data rate.
    """
    if part_number < 1:
        raise ValueError("part_number must be greater than 0")

    if part_number > 10_000:
        raise ValueError("part_number must be less than 10,000")

    # Make sure we never go above the maximum data rate or fall below the
    # minimum part size, even if the data rate is lower.
    data_rate = min(format_bytes_per_second, MAXIMUM_DATA_RATE)
    data_rate = max(data_rate, MINIMUM_PART_SIZE)

    # Calculate a scalar given our data rate. We will explain this step
    # futher on in the guides.
    scalar = -(2 * (125 * data_rate - 68_719_476_736)) / 8_334_583_375
    part_size = math.floor(scalar * pow(part_number, 2)) + data_rate

    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](/camera-to-cloud/how-to-upload-realtime#showing-our-work).
<Info title="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](/camera-to-cloud/how-to-upload-realtime#showing-our-work) cómo llegamos a esta fórmula.
</Info>

<Info title="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.



</Info>


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`**

```python title="Python"
def create_part_size_calculator(format_bytes_per_second: int) -> Callable[[int], int]:
    """
    Returns a function that takes in a `part_number` and returns a
    `part_size` based on `data_rate`.
    """

    # Make sure we never go above the maximum data rate or fall below the
    # minimum part size, even if the data rate is lower.
    data_rate = min(format_bytes_per_second, MAXIMUM_DATA_RATE)
    data_rate = max(data_rate, MINIMUM_PART_SIZE)

    static_scalar = -(2 * (125 * data_rate - 68_719_476_736)) / 8_334_583_375

    def part_size_calculator(part_number: int) -> int:
        """Calculates size in bytes of upload for `part_number`."""
        if part_number < 1:
            raise ValueError("part_number must be greater than 0")

        if part_number > 10_000:
            raise ValueError("part_number must be less than 10,000")

        return math.floor(static_scalar * pow(part_number, 2) + data_rate)

    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 partes | Bytes de carga útil | MB de carga útil | Total de bytes del archivo | Total de GB del archivo |
| ----------: | ------------: | ---------: | ----------------: | -------------: |
| 1 | 5 242 896 | 5,2 MB | 5 242 896 | 0,0 GB |
| 1000 | 21 575 817 | 21,6 MB | 10 695 361 357 | 10,7 GB |
| 5000 | 413 566 329 | 413,6 MB | 706 957 655 928 | 707,0 GB |
| 10000 | 1 638 536 679 | 1638,5 MB | 5 497 558 133 921 | 5497,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](https://www.wolframalpha.com/input?i=-%282+%28-68%2C719%2C476%2C736+%2B+125+12%2C750%2C000%29%29%2F8%2C334%2C583%2C375) y genera una tabla como esta:
| Total de partes | Bytes de carga útil | MB de carga útil | Total de bytes del archivo | Total de GB del archivo |
| ----------: | ------------: | ---------: | ----------------: | -------------: |
| 1 | 12 750 016 | 12,8 MB | 12 750 016 | 0,0 GB |
| 1000 | 28 857 758 | 28,9 MB | 18 127 308 783 | 18,1 GB |
| 5000 | 415 443 954 | 415,4 MB | 735 107 948 432 | 735,1 GB |
| 10 000 | 1 623 525 817 | 1623,5 MB | 5 497 558 133 958 | 5497,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 partes | Bytes de carga útil | MB de carga útil | Total de bytes del archivo | Total de GB del archivo |
| ----------: | ------------: | ---------: | ----------------: | -------------: |
| 1 | 280 000 008 | 280,0 MB | 280 000 008 | 0,3 GB |
| 1000 | 288 091 460 | 288,1 MB | 282 701 200 139 | 282,7 GB |
| 5000 | 482 286 516 | 482,3 MB | 1 737 245 341 542 | 1737,2 GB |
| 10 000 | 1 089 146 065 | 1089,1 MB | 5 497 558 133 870 | 5497,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:





```math
n^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`:

```math
n^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:

```math
Σ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](https://www.wolframalpha.com/input?i=%CE%A3n%5E2+%2B+r+where+n+%3D+1+to+10%2C000+and+r+%3D+5%2C242%2C880): `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:





```math
Σ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`:

```math
Σ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](https://www.math-only-math.com/sum-of-the-squares-of-first-n-natural-numbers.html) de calcular fácilmente la suma del cuadrado de los primeros `n` números naturales:

```math
Σn^2 = n(n+1)(2n+1)/6
```





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





```math
Σn^2 = (2n^3 + 3n^2 + n)/6
```

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

```math
Σxn^2 + r = x(2n^3 + 3n^2 + n)/6 + rn
```





Y finalmente establecemos nuestra nueva fórmula igual a 5 TiB:





```math
x(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](https://www.wolframalpha.com/input?i=x%282n%5E3+%2B+3n%5E2+%2B+n%29%2F6+%2B+r+*+n+%3D+5%2C497%2C558%2C138%2C880+solve+for+x+where+n+%3D+10%2C000):

```math
x = -(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](https://www.wolframalpha.com/input?i=x%282n%5E3+%2B+3n%5E2+%2B+n%29%2F6+%2B+r+*+n+%3D+5%2C497%2C558%2C138%2C880+solve+for+x+where+n+%3D+10%2C000+and+r+%3D+5%2C242%2C880) un escalar estático de:

```math
136,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:

```math
s = 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`**

```python title="Python"
math.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`**

```python title="Python"
import math
from datetime import datetime, timezone
from typing import Callable

# The minimum size, in bytes, for a single, non-final part upload.
MINIMUM_PART_SIZE = 5_242_880
# The maximum filesize in
MAXIMUM_PART_COUNT = 10_000
# The maximum size, in bytes, for an AWS upload.
MAXIMUM_FILE_SIZE = 5_497_558_138_880

# The data rate at which every part is an equal size, and could not
# be any uniformly larger without violating the maximum total file
# size if 10_000 parts were to be uploaded. it works out to
# ~549.8 MB per payload. By enforcing this we actually never need
# to check if a part exceeds the maximum allowed part size, as our
# parts will never exceed ~549.8 MB.
MAXIMUM_DATA_RATE = MAXIMUM_FILE_SIZE // MAXIMUM_PART_COUNT

def create_part_size_calculator(format_bytes_per_second: int) -> Callable[[int], int]:
    """
    Returns a function that takes in a `part_number` and returns a
    `part_size` based on `data_rate`.
    """
    ...

def upload_render(data_stream: DataStream, channel: int = 0) -> None:
    """
    Uploads an asset for data_stream, which is a custom IO class that pulls remaining
    upload data from an internal buffer or file, depending on how well the upload is
    keeping pace with the render.

    Uploads to `channel`
    """

    asset = c2c.asset_create(
        extension=data_stream.extension, 
        filetype=data_stream.mimetpye, 
        channel=channel,
        offset=datetime.now(timezone.utc) - data_stream.created_at()
    )

    calculate_part_size = create_part_size_calculator(data_stream.data_rate())
    next_part_number = 0

    while True:
        next_payload_size = calculate_part_size(next_part_number)

        # Waits until one or more chunks worth of data is ready for upload. Cache 
        # whether our data stream has completed writing the file, and the current 
        # number of bytes we have remaining to upload at this time.
        available_bytes, stream_complete = data_stream.wait_for_available_data(
            minimum_bytes=next_payload_size
        )

        # Build the list of parts to request based on our available data.
        parts = []
        while available_bytes > 0:
            payload_size = calculate_part_size(next_part_number)

            if available_bytes < payload_size and not stream_complete:
                break

            payload_size = min(payload_size, available_bytes)

            parts.append(
                c2c.RealtimeUploadPart(
                    part_number=next_part_number,
                    part_size=payload_size,
                    is_final=False
                )
            )

            available_bytes -= payload_size
            next_part_number += 1

        # If our stream is done writing, mark the last part as final.
        if stream_complete:
            parts[-1].is_final = True

        # Create the part URLs using the C2C endpoint.
        response = c2c.create_realtime_parts(
            asset_id=asset.id,
            asset_name=None if not stream_complete else data_stream.filename,
            asset_filesize=None if not stream_complete else data_stream.size(),
            parts=parts
        )

        # Upload each part to its URL.
        for part, part_url in zip(parts, response.upload_urls):
            part_data = data_stream.read(bytes=part.size)
            c2c.upload_chunk(part_data, part_url, data_stream.mimetype)

        if stream_complete:
            break

```




<Warning title="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](/camera-to-cloud/how-to-handle-errors) y [técnicas avanzadas de carga](/camera-to-cloud/how-to-advanced-uploads).
</Warning>


## 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](/camera-to-cloud/how-to-advanced-uploads) 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.