Instruções: Como fazer o upload (em tempo real)

Introdução

Com base em nosso conhecimento básico de upload, vamos explorar o upload de ativos em tempo real conforme são criados. Essa abordagem possibilita fazer upload de arquivos durante gravação, renderização ou streaming antes de conhecer o tamanho final.

A API de uploads em tempo real permite que os ativos se tornem reproduzíveis no Frame.io apenas alguns segundos após a conclusão da gravação, aprimorando significativamente a eficiência do fluxo de trabalho.

Vídeo de demonstração

Para uma visualização rápida desta funcionalidade, assista ao nosso vídeo de demonstração. A demonstração mostra uma renderização sendo carregada do Adobe Media Encoder em tempo real, com o vídeo reproduzível no Frame.io apenas 5 segundos após a conclusão da renderização.

Pré-requisitos

Caso ainda não tenha feito isso, consulte o guia Implementação do C2C: Configuração. Você precisará do access_token obtido durante o processo de autenticação e autorização. Usaremos o mesmo ativo de teste do guia de upload básico para nossos exemplos. Recomenda-se familiaridade com o guia de Uploads básicos, pois desenvolveremos esses conceitos.

Criar um ativo em tempo real

Os uploads em tempo real começam com um processo modificado de criação de ativos. Ao criar o ativo, defina is_realtime_upload como true e omita o parâmetro filesize (ou defina como null), pois o tamanho final não é conhecido durante a criação:

${
>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
Especificação do ponto de acesso da API

A documentação para /v2/devices/assets pode ser encontrada aqui.

Extensão e nome do arquivo

Ativos em tempo real requerem uma extensão de arquivo. Se o nome do arquivo não for conhecido ao criar o ativo, você pode usar o campo extension (formato: '.mp4'). Essa abordagem é preferível quando você planeja atualizar o nome do ativo posteriormente.

A resposta para ativos em tempo real é simplificada em comparação à criação de ativos padrão:

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

Observe que upload_urls está ausente. Para uploads em tempo real, geraremos URLs de upload por demanda conforme o arquivo é criado.

Solicitar URLs de upload

Vamos solicitar um URL para a primeira metade do nosso arquivo (10.568.125 bytes), usando o asset_id da resposta 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
Especificação do ponto de acesso da API

A documentação para /v2/devices/assets/{asset_id}/realtime_upload/parts pode ser encontrada aqui.

Entender os parâmetros da solicitação:

  • parts: uma lista de partes de upload para as quais precisamos de URLs. Solicitar vários URLs em uma única chamada melhora a eficiência.

  • number: o número sequencial da parte, começando em 1. Os números podem ser pulados e as partes enviadas em qualquer ordem, mas serão montadas sequencialmente. Não pode exceder 10.000 (limite da AWS). * size: tamanho da parte em bytes. Deve estar em conformidade com as restrições de upload multiparte da AWS. * is_final: indica se esta é a parte final do arquivo.

A resposta contém as URLs de upload solicitados:

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

A lista upload_urls corresponde diretamente à ordem da solicitação parts.

Agora faça upload do primeiro bloco como no guia de uploads básicos:

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

Em seguida, solicite um URL para a segunda e ú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 adições importantes:

  • is_final é definido como true para a última parte, sinalizando que o upload será concluído após este bloco
  • asset_filesize fornece o tamanho total do arquivo, que é necessário quando qualquer parte tem is_final: true

Após receber o URL na resposta:

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

Faça upload do bloco 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 @-
Manuseio da parte final

Quando a parte final é enviada, o Frame.io inicia a montagem do arquivo completo. Este processo inclui um período de tolerância de 60 segundos para que as partes restantes sejam concluídas. Recomendamos fazer upload da parte final somente depois que todas as outras partes foram enviadas com sucesso.

Pronto! Navegue para Frame.io para ver seu ativo em tempo real carregado com sucesso. 🎉

Gerenciar nomes de ativos

Se o nome do arquivo não for conhecido durante a criação do ativo, você pode usar o campo extension sem um 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

O sistema atribuirá um nome padrão:

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

Você pode atualizar este nome incluindo um campo asset_name ao solicitar URLs de upload:

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

O nome só será atualizado se o ativo ainda tiver seu nome padrão. Se foi renomeado na interface do Frame.io ou atualizado anteriormente, a solicitação será ignorada.

Otimizar solicitações de URL

Para maior eficiência, solicite URLs para quantas partes você tiver dados disponíveis no momento, em vez de individualmente. Esta abordagem é particularmente valiosa para arquivos grandes onde a velocidade de upload pode ficar atrás da geração de dados.

Processar cabeçalhos de arquivos de mídia

Alguns formatos de mídia exigem cabeçalhos no início do arquivo que não são escritos até que todo o arquivo seja concluído. Isso gera um desafio quando o cabeçalho é menor que o tamanho mínimo de parte da AWS de 5 MiB (5.242.880 bytes).

Nossa recomendação:

  1. Reserve os primeiros 5.242.880 bytes de dados de mídia sem fazer upload
  2. Comece fazendo upload de partes iniciando com part_number=2
  3. Quando o arquivo estiver completo, adicione o cabeçalho aos dados reservados
  4. Solicite um URL para part_number=1 e faça upload deste bloco combinado

Esta abordagem garante que seu primeiro bloco atenda ao requisito de tamanho mínimo preservando a estrutura adequada do arquivo.

Dimensionar tamanho da parte para desempenho ideal

A AWS impõe limites que afetam a estratégia de upload:

  • Tamanho máximo de arquivo: 5 TiB (5.497.558.138.880 bytes)
  • Número máximo de partes: 10.000
  • Tamanho mínimo da parte: 5 MiB (5.242.880 bytes)

Um tamanho fixo de peça implica em compromissos:

  • Usar o tamanho mínimo (5 MiB) para todas as 10.000 partes limita o tamanho total do arquivo para aproximadamente 52,4 GB
  • Distribuir uniformemente o tamanho máximo do arquivo exigiria blocos de aproximadamente 550 MB, muito grandes para streaming eficiente de arquivos menores

Precisamos de uma fórmula que equilibre essas restrições, começando com partes pequenas para uploads responsivos, garantindo que seja possível lidar com arquivos muito grandes, se necessário.

Fórmula de tamanho de parte recomendado

Esta é nossa abordagem sugerida em 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

… onde part_number está entre 1 e 10_000, inclusive, e format_bytes_per_second é o número médio esperado de bytes que o arquivo deve consumir por segundo. Explicaremos como a fórmula foi criada mais adiante.

Valor escalar

A variável scalar e o cálculo podem ser um pouco confusos à primeira vista, mas é uma ferramenta matemática que garante que, independentemente do valor usado para format_bytes_per_second, se alimentarmos todos os valores part_number permitidos de 1 a 10_0000 na função, receberemos um conjunto de valores que totaliza exatamente nosso limite de tamanho de arquivo de 5 TiB — bem, o mais exato possível. Mostramos nosso trabalho mais adiante sobre como chegamos a essa fórmula.

Arredondamento por número inteiro

Ao usar arredondamento por número inteiro, deixamos alguns bytes de lado, mas garantimos que o arredondamento regular em 10.000 partes não exceda acidentalmente nosso tamanho máximo de arquivo permitido. No máximo, 10.000 bytes ou 10 KB serão deixados de lado dessa forma, uma compensação aceitável.

As características importantes dessa fórmula são:

  • Ao fazer upload de 10.000 partes, a quantidade total de dados carregados ficará dentro de 10 KB do nosso limite de tamanho de arquivo de 5 TiB.
  • Otimiza conteúdos menores e mais eficientes no início para aumentar a capacidade de resposta para clipes curtos e de duração média.
  • Clipes muito longos terão capacidade de resposta reduzida entre o final da gravação de um arquivo e ele se tornar reproduzível no Frame.

A compensação entre o segundo e o terceiro ponto é reduzida pelo fato de que a maioria dos clipes não atingirá o tamanho em que o terceiro ponto entra em ação. Estamos trocando capacidade de resposta aumentada da MAIORIA dos arquivos por capacidade de resposta reduzida de muito poucos.

Uma versão mais avançada e eficiente da nossa fórmula (que gera uma função anônima part_size_calculator com nosso escalar estático e taxa de dados pré-computados e incorporados) pode ser assim:

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

Como a fórmula funciona.

Vamos analisar as características de saída da fórmula acima em vários tipos de arquivo comuns.

Exemplo 1: Formato da web

Para formatos reproduzíveis na web com taxa de aproximadamente 5,3 MB/s ou menos (a maioria dos arquivos H.264/H.265/HEVC), obteremos uma progressão de tamanho de conteúdo semelhante a:

Total de partesBytes de conteúdoMB de conteúdoTotal de bytes do arquivoTotal de GB do arquivo
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
Chave das colunas da tabelaTotal Parts: o número total de partes de arquivo enviadas para a AWS. - Payload Bytes: o tamanho do conteúdo da chamada PUT da AWS quando part_number é igual a Total Parts. - Payload MB: Como Payload Bytes, mas em megabytes. - Total File Bytes: o número total de bytes enviados para o arquivo quando as partes sequenciais Total Parts foram enviadas. - Total File GB: Como Total File Bytes, mas em GB.

Esses valores são bem equilibrados para uploads em tempo real, especialmente de codecs de reprodução na web como H.264. A maioria ficará abaixo de 10,7 GB e, portanto, será concluída em até 1.000 partes. O tamanho do conteúdo nunca excederia 21,6 MB.

Mesmo que dividíssemos nossas partes ao meio, o tamanho do conteúdo ainda assim nunca ultrapassaria 413,5 MB. O upload totalizaria 707 GB, mais do que suficiente para a maioria dos arquivos da web.

É apenas quando nos aproximamos do final da contagem de partes permitidas que o tamanho do arquivo começa a aumentar drasticamente. No entanto, nunca excede 1,7 GB, bem abaixo do limite da AWS de 5 GiB por parte.

Exemplo 2: Prores 422 LT Prores 422 LT tem uma taxa de dados de 102 Mbps e gera uma tabela como esta:

Total de partesBytes de conteúdoMB de conteúdoTotal de bytes do arquivoTotal de GB do arquivo
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

Esta tabela revela propriedades úteis comparadas à nossa fórmula otimizada para web. Nas primeiras 1.000 partes, conseguimos fazer upload de 8 GB a mais de arquivo. Conteúdos iniciais maiores significam que não precisaremos solicitar URLs muito rapidamente no início, tornando o upload mais eficiente para a taxa de dados mais alta. O tamanho do nosso conteúdo no final do processo de upload continua sendo grande.

Exemplo 2: Camera raw

Finalmente, vamos testar um formato Camera RAW que tem uma taxa de dados de 280 MB/s. Com dados chegando tão rapidamente, tentar fazer upload em blocos de 5 MiB no início simplesmente não faz sentido:

Total de partesBytes de conteúdoMB de conteúdoTotal de bytes do arquivoTotal de GB do arquivo
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

Além do conteúdo inicial ser mais eficiente, estamos economizando mais de meio gigabyte na extremidade superior, o que tornará essas chamadas de rede menos suscetíveis a eventos adversos na rede.

Mostrando nosso trabalho

Antes de reunir tudo em um exemplo de carregador, vamos ver como chegamos à nossa fórmula.

O que precisávamos fazer era criar uma fórmula que trocasse conteúdos úteis grandes e pesados no final do nosso limite de partes, que a maioria dos uploads nunca alcançará, por conteúdos úteis leves e eficientes no início, onde todos os uploads podem se beneficiar. Ao mesmo tempo, queríamos garantir que nosso algoritmo chegue perto do limite de tamanho de arquivo de 5 TiB exatamente no número da parte 10.000.

Era hora de usar um pouco de cálculo.

Queremos que nosso gráfico cresça exponencialmente, então nossa fórmula provavelmente deve ser algo como:

n2n^2

… onde n é o número da parte. Também queremos garantir que cada parte seja, no mínimo, a taxa de dados para nossa fórmula, que chamaremos de r:

n2+rn^2 + r

Agora precisamos encontrar uma fórmula que possa nos dizer a soma desta fórmula para os primeiros 10.000 números naturais (1, 2, 3, …). O símbolo sigma Σ denota somatória. Vamos adicioná-lo à nossa fórmula:

Σxn2+rΣxn^2 + r

… e redefinir n como a série de números naturais entre 1 e 10.000, inclusive. A equação ainda não é muito útil para nós. Ela tem a forma intuitiva correta, mas se definirmos n=10,000 e r=5,242,880 como queremos, ela apenas gera um resultado: 385,812,135,000 (385 GB). Não apenas o resultado está muito abaixo do nosso limite de tamanho de arquivo de 5 TiB, não há como manipular a fórmula para gerar esse resultado.

Vamos nos dar um controle para ajustar:

Σxn2+rΣxn^2 + r

… onde x é um escalar que podemos resolver para obter 5 TiB como resultado. Agora podemos definir a equação igual ao nosso limite de tamanho de arquivo e resolver para x:

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

Frequentemente, as somatórias devem ser resolvidas iterativamente, como em um loop for ou while. Mas acontece que existe uma fórmula perfeita para nós: uma forma conhecida de calcular facilmente a soma do quadrado para os primeiros n números naturais:

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

Reorganizá-la em um polinômio facilita a visualização:

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

Podemos adicionar nossas variáveis, x e r, a ambos os lados:

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

E finalmente definimos nossa nova 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

Agora tudo o que precisamos fazer é resolver para x definindo n=10.000, nossa contagem total de partes. Isso nos dará uma forma de calcular um escalar estático para uma determinada taxa de dados. Em vez de fazer isso manualmente, vamos inserir no Wolfram Alpha:

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

Agora estamos chegando a algum lugar! Se nossa taxa de dados fosse o tamanho mínimo da parte (5 MiB), obteríamos um escalar estático de:

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

No mundo da computação, isso representa um valor float64 de 16.33293799427617. Nossa fórmula para determinar o tamanho da parte nesta instância seria:

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

Onde s é o tamanho da nossa parte.

Ainda temos mais um problema. No mundo real, não podemos ter um conteúdo com bytes não inteiros. Precisamos arredondar cada valor. Vamos usar Python e arredondar para baixo:

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

Chegamos a um exemplo concreto da função original fornecida neste guia.

Criar um carregador básico

Vamos dar uma olhada em um pseudocódigo simples semelhante ao python para fazer upload de um arquivo sendo renderizado em tempo real, usando tudo o que aprendemos neste guia:

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
Upload avançado

O código acima demonstra apenas o fluxo básico de fazer upload de um arquivo em tempo real. Na realidade, essa lógica precisará ser aprimorada com tratamento de erros e técnicas de upload avançado.

Próximas etapas

Os uploads em tempo real oferecem uma forma de tornar sua integração o mais responsiva possível, com ativos ficando reproduzíveis no Frame.io segundos após terminarem de gravar. Um guia posterior abordará técnicas avançadas e requisitos de upload. Embora tenha sido escrito pensando em uploads básicos, a maior parte do guia ainda será aplicável aos uploads em tempo real.

Se ainda não o fez, recomendamos que entre em contato com nossa equipe e, em seguida, siga para o próximo guia. Estamos ansiosos para ter notícias suas!