Leitfaden: Uploads (Echtzeit)

Einführung

Aufbauend auf unseren Grundkenntnissen zum Hochladen wollen wir uns nun damit befassen, wie man Assets in Echtzeit hochlädt, während sie erstellt werden.Mit diesem Ansatz werden Dateien während der Aufnahme, des Renderns oder des Streamings hochgeladen, noch bevor deren endgültige Größe bekannt ist.

Die Echtzeit-Upload-API gestattet es, dass Assets bereits wenige Sekunden nach Abschluss der Aufnahme in Frame.io abgespielt werden können, was die Effizienz des Workflows erheblich steigert.

Demovideo

Um sich einen kurzen Überblick über diese Funktion zu verschaffen, sehen Sie sich bitte unsere Videovorführung an.Die Demo zeigt, wie ein Rendering in Echtzeit aus Adobe Media Encoder hochgeladen wird, wobei das Video bereits 5 Sekunden nach Abschluss des Renderings in Frame.io abgespielt werden kann.

Voraussetzungen

Wenn Sie es noch nicht getan haben, lesen Sie bitte den Leitfaden C2C implementieren: Einrichtung.Sie benötigen den access_token, den Sie während des Authentifizierungs- und Autorisierungsprozesses erhalten haben.Für unsere Beispiele verwenden wir das Test-Asset aus dem Leitfaden zu einfachen Uploads.Es wird empfohlen, sich mit dem Leitfaden zu einfachen Uploads vertraut zu machen, da wir auf diesen Konzepten aufbauen werden.

Ein Echtzeit-Asset erstellen

Echtzeit-Uploads beginnen mit einem angepassten Verfahren zur Erstellung von Assets.Legen Sie beim Erstellen des Assets is_realtime_upload auf true fest und lassen Sie den Parameter filesize weg (oder setzen Sie ihn auf null), da die endgültige Größe zum Zeitpunkt der Erstellung noch nicht bekannt ist:

${
>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
Spezifikation des API-Endpunkts

Die Dokumentation für /v2/devices/assets findet sich hier.

Erweiterung und Dateiname

Echtzeit-Assets benötigen eine Dateierweiterung.Falls der Dateiname beim Erstellen des Assets noch nicht bekannt ist, können Sie stattdessen das Feld Erweiterung verwenden (Format: '.mp4').Dieser Ansatz ist vorzuziehen, wenn Sie beabsichtigen, den Namen des Assets später zu ändern.

Die Vorgehensweise bei der Erstellung von Echtzeit-Assets ist im Vergleich zur Erstellung von Standard-Assets vereinfacht:

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

Beachten Sie, dass upload_urls fehlt – für Echtzeit-Uploads generieren wir die Upload-URLs nach Bedarf, sobald die Datei erstellt wird.

Upload-URLs anfordern

Lassen Sie uns eine URL für die erste Hälfte unserer Datei (10.568.125 Byte) anfordern, wobei wir die asset_id aus der vorherigen Antwort verwenden:

${
>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
Spezifikation des API-Endpunkts

Die Dokumentation zu /v2/devices/assets/{asset_id}/realtime_upload/parts finden Sie hier.

Die Anfrageparameter verstehen:

  • parts: Eine Liste der Upload-Teile, für die wir URLs benötigen.Die Anfrage mehrerer URLs in einem einzigen Aufruf erhöht die Effizienz.

  • number: Die fortlaufende Artikelnummer, beginnend mit 1.Nummern können übersprungen und Teile in beliebiger Reihenfolge hochgeladen werden, sie werden jedoch der Reihe nach zusammengesetzt.Darf 10.000 nicht überschreiten (AWS-Limit).* size: Teilgröße in Byte.Die Einschränkungen für mehrteilige Uploads bei AWS müssen eingehalten werden.* is_final: Gibt an, ob es sich um den letzten Dateiteil handelt.

Die Antwort enthält die angeforderten Upload-URLs:

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

Die Liste upload_urls entspricht direkt der Reihenfolge der Teileanfragen unter parts.

Laden Sie nun den ersten Chunk wie im Leitfaden zu einfachen Uploads beschrieben hoch:

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

Fordern Sie als Nächstes eine URL für den zweiten und letzten Teil an:

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

Beachten Sie folgende wichtige Ergänzungen:

  • Für den letzten Teil wird is_final auf true gesetzt, was bedeutet, dass der Upload nach diesem Chunk abgeschlossen sein wird
  • asset_filesize gibt die gesamte Dateigröße an, die erforderlich ist, wenn ein Teil is_final: true hat

Nachdem Sie die URL in der Antwort erhalten haben:

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

Laden Sie den letzten Chunk hoch:

$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 @-
Den letzten Teil verarbeiten

Sobald der letzte Teil hochgeladen ist, beginnt Frame.io mit der Zusammenführung der vollständigen Datei.Dieser Vorgang umfasst eine Nachfrist von 60 Sekunden, damit noch ausstehende Teile abgeschlossen werden können.Wir empfehlen, den letzten Teil erst dann hochzuladen, wenn alle anderen Teile erfolgreich hochgeladen wurden.

Das ist alles!Rufen Sie Frame.io auf, um Ihr erfolgreich hochgeladenes Echtzeit-Asset anzuzeigen.🎉

Asset-Namen verwalten

Falls der Dateiname bei der Erstellung des Assets noch nicht bekannt ist, können Sie das Feld extension ohne name verwenden:

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

Das System weist dann einen Standardnamen zu:

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

Sie können diesen Namen aktualisieren, indem Sie bei der Anfrage von Upload-URLs ein Feld asset_name angeben:

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

Der Name wird nur aktualisiert, wenn das Asset noch seinen Standardnamen trägt; wurde es in der Frame.io-Benutzeroberfläche umbenannt oder bereits zuvor aktualisiert, wird die Anfrage ignoriert.

URL-Anfragen optimieren

Um die Effizienz zu steigern, rufen Sie die URLs für so viele Teile ab, wie Ihnen derzeit Daten vorliegen, anstatt sie einzeln abzufragen.Dieser Ansatz ist besonders bei großen Dateien von Vorteil, bei denen die Upload-Geschwindigkeit hinter der Datengenerierung zurückbleiben könnte.

Header für Mediendateien verarbeiten

Bei einigen Medienformaten sind am Anfang der Datei Header erforderlich, die erst geschrieben werden, wenn die gesamte Datei vollständig ist.Dies stellt eine Herausforderung dar, wenn der Header kleiner ist als die von AWS festgelegte Mindestgröße von 5 MiB (5.242.880 Byte).

Unsere Empfehlung:

  1. Reservieren Sie die ersten 5.242.880 Byte der Mediendaten, ohne sie hochzuladen
  2. Beginnen Sie mit dem Hochladen der Teile, beginnend mit part_number=2
  3. Wenn die Datei vollständig ist, stellen Sie den Header an den Anfang der reservierten Daten
  4. Fordern Sie eine URL für part_number=1 an und laden Sie diesen kombinierten Chunk hoch

Dieser Ansatz stellt sicher, dass Ihr erster Chunk die Mindestgrößenanforderung erfüllt und gleichzeitig die korrekte Dateistruktur beibehalten wird.

Teilgröße für optimale Leistung skalieren

AWS legt Limits fest, die sich auf die Upload-Strategie auswirken:

  • Maximale Dateigröße: 5 TiB (5.497.558.138.880 Byte)
  • Maximale Anzahl Teile: 10.000
  • Minimale Teilgröße: 5 MiB (5.242.880 Byte)

Eine feste Teilgröße schafft Kompromisse:

  • Bei Verwendung der Mindestgröße (5 MiB) für alle 10.000 Teile wird die Gesamtdateigröße auf ca. 52,4 GB begrenzt
  • Um die maximale Dateigröße gleichmäßig zu verteilen, wären Chunks von etwa 550 MB erforderlich, die für ein effizientes Streaming kleinerer Dateien zu groß sind

Wir benötigen eine Formel, die diese Begrenzungen in Einklang bringt: Sie sollte zunächst kleine Teile für responsive Uploads nutzen und gleichzeitig sicherstellen, dass wir bei Bedarf auch sehr große Dateien verarbeiten können.

Empfohlene Formel für die Teilgröße

Hier ist unser Lösungsvorschlag 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

… wobei part_number zwischen 1 und 10_000 (einschließlich) liegt und format_bytes_per_second die voraussichtliche durchschnittliche Anzahl an Bytes angibt, die Ihre Datei pro Sekunde verbrauchen wird.Wir werden später noch näher darauf eingehen, wie man zu dieser Formel gelangt ist.

Skalarer Wert

Die Variable scalar und die Berechnung mögen auf den ersten Blick etwas verwirrend wirken, doch handelt es sich um ein mathematisches Hilfsmittel, das sicherstellt, dass wir – unabhängig davon, welchen Wert wir für format_bytes_per_second verwenden – bei Eingabe aller zulässigen Werte für part_number von 1 bis 10_000 in die Funktion eine Reihe von Werten erhalten, deren Summe genau unserem Dateigrößenlimit von 5 TiB entspricht – nun ja, so genau wie möglich.Im Folgenden erläutern wir näher, wie wir zu dieser Formel gelangt sind.

Auf die nächste ganze Zahl abrunden

Durch die Verwendung der Abrundung auf die nächste ganze Zahl lassen wir zwar einige Bytes ungenutzt, stellen jedoch sicher, dass eine reguläre Rundung bei Werten über 10.000 nicht versehentlich dazu führt, dass wir unsere maximal zulässige Dateigröße überschreiten.Auf diese Weise bleiben höchstens 10.000 Byte bzw. 10 KB ungenutzt – ein akzeptabler Kompromiss.

Die wesentlichen Merkmale dieser Formel sind:

  • Beim Hochladen von 10.000 Teilen wird die Gesamtdatenmenge weniger als 10 KB unter unserem Dateigrößenlimit von 5 TiB liegen.
  • Optimiert zu Beginn auf kleinere, effizientere Payloads, um die Reaktionsgeschwindigkeit bei kurzen und mittellangen Clips zu erhöhen.
  • Bei sehr langen Clips kommt es zu einer verzögerten Reaktionszeit zwischen dem Ende des Schreibvorgangs und dem Zeitpunkt, zu dem der Clip im Frame wiedergegeben werden kann.

Der Kompromiss zwischen dem zweiten und dritten Punkt wird dadurch gemildert, dass die meisten Clips nicht die Größe erreichen, bei der Punkt drei zum Tragen kommt.Wir tauschen eine verbesserte Reaktionsgeschwindigkeit bei den MEISTEN Dateien gegen eine geringere Reaktionsgeschwindigkeit bei einigen wenigen ein.

Eine weiterentwickelte und effizientere Version unserer Formel (die eine anonyme Funktion part_size_calculator generiert, in der unser statischer Skalar und die Datenrate bereits vorberechnet und integriert sind) könnte wie folgt aussehen:

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

Wie sich die Formel bewährt.

Betrachten wir die Ausgabeeigenschaften der obigen Formel für verschiedene gängige Dateiformate.

Beispiel 1: Webformat

Bei im Web abspielbaren Formaten mit einer Bitrate von ca. 5,3 MB/s oder weniger (die meisten H.264-/H.265-/HEVC-Dateien) ergibt sich folgende Entwicklung der Payload-Größe:

Teile insgesamtPayload in BytePayload in MBGesamte Datei in ByteGesamte Datei in GB
15.242.8965,2 MB5.242.8960,0 GB
10002157581721,6 MB1069536135710,7 GB
5000413566329413,6 MB706957655928707,0 GB
1000016385366791.638,5 MB54975581339215.497,6 GB
Table columns key (Legende zu den Tabellenspalten) – Total Parts (Teile insgesamt): Die Gesamtzahl der auf AWS hochgeladenen Dateiteile.- Payload Bytes (Payload in Byte): Die Größe der AWS-PUT-Payload, wenn part_number dem Wert von Total Parts entspricht.- Payload MB (Payload in MB): Wie Payload Bytes, aber in Megabyte.- Total File Bytes (Gesamte Datei in Byte): Die Gesamtzahl der Bytes, die für die Datei hochgeladen wurden, wenn die Total Parts als aufeinanderfolgende Teile hochgeladen wurden.- Total File GB (Gesamte Datei in GB): Wie Total File Bytes, aber in GB.

Diese Werte sind für Echtzeit-Uploads gut ausbalanciert, insbesondere bei Codecs für die Web-Wiedergabe wie H.264; die meisten liegen unter 10,7 GB und sind daher innerhalb von 1.000 Teilen abgeschlossen.Die Payload-Größe würde niemals 21,6 MB überschreiten.

Wenn wir uns durch die Hälfte unserer Teile durcharbeiten würden, würde die Payload-Größe dennoch niemals 413,5 MB überschreiten.Der Upload würde insgesamt 707 GB betragen, was für die allermeisten Webdateien mehr als ausreichend ist.

Erst wenn wir uns dem Ende unserer zulässigen Teileanzahl nähern, beginnt die Dateigröße, stark anzusteigen.Allerdings überschreitet sie niemals 1,7 GB und liegt damit deutlich unter dem AWS-Limit von 5 GiB pro Teil.

Beispiel 2: Prores 422 LT Prores 422 LT hat eine Datenrate von 102 MBit/s und generiert eine Tabelle wie folgt:

Teile insgesamtPayload in BytePayload in MBGesamte Datei in ByteGesamte Datei in GB
11275001612,8 MB127500160,0 GB
10002885775828,9 MB1812730878318,1 GB
5000415443954415,4 MB735107948432735,1 GB
1000016235258171.623,5 MB54975581339585.497,6 GB

Diese Tabelle zeigt nützliche Eigenschaften im Vergleich zu unserer Web-optimierten Formel auf.Innerhalb der ersten 1.000 Teile können wir 8 GB mehr der Datei hochladen.Größere anfängliche Payloads bedeuten, dass wir zu Beginn nicht zu schnell URLs abfragen müssen, wodurch der Upload bei der höheren Datenrate effizienter wird.Die Größe unserer Payload bleibt gegen Ende des Upload-Vorgangs weiterhin groß.

Beispiel 2: Camera Raw

Probieren wir zum Schluss ein Camera-Raw-Format mit einer Datenübertragungsrate von 280 MB/s aus.Angesichts dieser rasanten Datenübertragung ergibt es einfach keinen Sinn, zu Beginn zu versuchen, die Daten in 5-MiB-Chunks hochzuladen:

Teile insgesamtPayload in BytePayload in MBGesamte Datei in ByteGesamte Datei in GB
1280000008280,0 MB2800000080,3 GB
1000288091460288,1 MB282701200139282,7 GB
5000482286516482,3 MB17372453415421.737,2 GB
1000010891460651.089,1 MB54975581338705.497,6 GB

Frühe Payloads sind nicht nur effizienter, sondern wir sparen zudem am oberen Ende über ein halbes Gigabyte ein, wodurch diese Netzwerkaufrufe weniger anfällig für Störungen im Netzwerk sind.

Unsere Arbeit präsentieren

Bevor wir alles in einem Beispiel-Uploader zusammenführen, wollen wir uns zunächst ansehen, wie wir zu unserer Formel gelangt sind.

Wir mussten eine Formel entwickeln, bei der große, ressourcenintensive Payloads am Ende der uns zur Verfügung stehenden Teileanzahl – die die meisten Uploads niemals erreichen werden – gegen leichte, effiziente Payloads am Anfang eingetauscht werden, von denen jeder Upload profitieren kann.Gleichzeitig wollten wir sicherstellen, dass unser Algorithmus genau bei der Teilenummer 10.000 in den Bereich des Dateigrößenlimits von 5 TiB fällt.

Es war an der Zeit, sich mit der Analysis zu befassen.

Wir möchten, dass unser Graph exponentiell wächst, daher sollte unsere Formel in etwa so aussehen:

n2n^2

… wobei n die Teilnummer ist.Wir möchten außerdem sicherstellen, dass jeder Teil mindestens die Datenrate unserer Formel erreicht, die wir mit r bezeichnen:

n2+rn^2 + r

Nun müssen wir eine Formel finden, die uns die Summe dieser Formel für die ersten 10.000 natürlichen Zahlen (1, 2, 3 …) angibt.Das Sigma-Zeichen Σ steht für die Summe.Fügen wir es unserer Formel hinzu:

Σxn2+rΣxn^2 + r

… und definieren n als die Folge der natürlichen Zahlen zwischen 1 und 10.000 (einschließlich).Diese Gleichung ist für uns noch nicht besonders nützlich.Die Formel ist zwar intuitiv richtig, doch wenn wir n=10,000 und r=5,242,880 wie gewünscht eingeben, gibt sie einfach ein Ergebnis aus: 385,812,135,000 (385 GB).Das Ergebnis liegt nicht nur weit unter unserer Dateigrößenbeschränkung von 5 TiB, es gibt auch keine Möglichkeit, die Formel so anzupassen, dass sie dieses Ergebnis liefert.

Versuchen wir doch einmal, am Rad zu drehen:

Σxn2+rΣxn^2 + r

… wobei x ein Skalar ist, den wir berechnen können, um als Ergebnis 5 TiB zu erhalten.Nun können wir die Gleichung unserem Dateigrößenlimit gleichsetzen und nach x lösen:

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

Häufig müssen Summen iterativ berechnet werden, beispielsweise in einer for- oder while-Schleife.Es stellt sich jedoch heraus, dass es für uns eine perfekte Formel gibt: eine bekannte Methode, um die Summe der Quadrate der ersten n natürlichen Zahlen günstig zu berechnen:

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

Wenn man sie in ein Polynom umformuliert, lässt sie sich leichter überblicken:

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

Wir können unsere Variablen x und r auf beiden Seiten hinzufügen:

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

Und schließlich setzen wir unsere neue Formel gleich 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

Nun müssen wir nur noch x berechnen, indem wir n=10.000 setzen, also unsere Gesamtteilzahl.Auf diese Weise können wir einen statischen Skalar für eine bestimmte Datenrate berechnen.Anstatt dies von Hand zu erledigen, geben wir es in Wolfram Alpha ein:

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

Jetzt kommen wir der Sache schon näher!Wenn unsere Datenrate der minimalen Teilgröße (5 MiB) entspräche, würden wir einen statischen Skalar erhalten von:

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

In der Welt der Informatik entspricht dies einem Float64-Wert von 16.33293799427617.Unsere Formel zur Bestimmung der Teilegröße würde in diesem Fall wie folgt lauten:

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

Wobei s unsere Teilgröße ist.

Wir haben noch ein weiteres Problem.In der Praxis ist eine Payload mit nicht ganzzahligen Bytes nicht zulässig.Wir müssen jeden Wert runden.Wir verwenden Python und runden ab:

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

Wir sind nun bei einem konkreten Beispiel für die in dieser Anleitung vorgestellte ursprüngliche Funktion angelangt.

Einen einfachen Uploader aufbauen

Werfen wir einen Blick auf einen einfachen, Python-ähnlichen Pseudocode zum Hochladen einer Datei, die in Echtzeit gerendert wird, und nutzen dabei alles, was wir in dieser Anleitung gelernt haben:

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
Erweiterte Uploads

Der obige Code veranschaulicht lediglich den grundlegenden Ablauf des Hochladens einer Datei in Echtzeit.In der Praxis muss diese Logik jedoch um Fehlerbehandlung und erweiterte Upload-Techniken erweitert werden.

Als Nächstes

Echtzeit-Uploads bieten die Möglichkeit, Ihre Integration so responsiv wie möglich zu gestalten, da die Dateien bereits wenige Sekunden nach Abschluss der Aufnahme in Frame.io abgespielt werden können.In einer späteren Anleitung werden erweiterte Upload-Techniken und -Anforderungen behandelt.Auch wenn diese Anleitung ursprünglich für einfache Uploads verfasst wurde, gilt der Großteil der darin enthaltenen Informationen dennoch für Echtzeit-Uploads.

Falls Sie dies noch nicht getan haben, empfehlen wir Ihnen, sich an unser Team zu wenden und anschließend mit der nächsten Anleitung fortzufahren.Wir freuen uns darauf, von Ihnen zu hören!