Oletko koskaan toivonut voivasi esikatsella pyöräilyreittiä ennen kuin ajat sen? Rakensimme automaattisen järjestelmän, joka luo upean lentovideon jokaisen Party Onbicin ryhmäajon reitistä, ja näin pyöräilijät saavat elokuvamaisen ennakkokatsauksen siihen, mitä matkalla on odotettavissa.

Haaste

Kun järjestät pyöräilytapahtumaa tai liityt sellaiseen, reitin ymmärtäminen on ratkaisevan tärkeää. Staattiset kartat auttavat, mutta ne eivät välitä kokemusta siitä, millaista reitillä on oikeasti ajaa. Halusimme antaa käyttäjille tavan ”lentää” reitin läpi virtuaalisesti ennen kuin he sitoutuvat ajoon.

Ratkaisumme: videon renderöinti headless-selaimella

Rakensimme Node.js-palvelun, joka ajaa headless Chrome -selainta Puppeteerin avulla, renderöi reitin interaktiiviselle MapLibre GL -kartalle ja tallentaa kuvia, kun virtuaalinen kamera lentää reittiä pitkin. Näin se toimii:

1. Reitin interpolointi

Pyöräilyreitillä voi olla tuhansia koordinaattipisteitä. Jotta saamme 15 sekunnin pituisen sujuvan videon 30 FPS:n kuvataajuudella, tarvitsemme täsmälleen 450 kuvaa. Käytämme etäisyyteen perustuvaa interpolointia, jotta näytteet otetaan reitiltä tasaisesti:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Calculate cumulative distances using Haversine formula
const distances = [0];
for (let i = 1; i < coordinates.length; i++) {
  const dist = haversineDistance(coordinates[i-1], coordinates[i]);
  totalDistance += dist;
  distances.push(totalDistance);
}

// Sample at exactly totalFrames points
for (let frame = 0; frame < totalFrames; frame++) {
  const targetDist = (frame / (totalFrames - 1)) * totalDistance;
  // Interpolate position at this distance...
}

2. Kameran animointi tasaisella suunnalla

Jos kamera vain osoittaa kulkusuuntaan, mutkittelevilla reiteillä liike on nykivää. Tasoitamme kameran suuntaa 12 kuvan liukuvalla keskiarvolla ja käsittelemme erikseen kohdan, jossa suunta kiertyy 360°:sta 0°:een:

1
2
3
4
5
6
7
// Use sin/cos components for circular averaging
for (let j = i - smoothWindow; j <= i + smoothWindow; j++) {
  const rad = rawBearings[j] * Math.PI / 180;
  sinSum += Math.sin(rad);
  cosSum += Math.cos(rad);
}
const avgBearing = Math.atan2(sinSum/count, cosSum/count) * 180 / Math.PI;

3. Renderöinti MapLibre GL:llä

Reitti renderöidään kauniin Stadia Maps -pohjakartan päälle, ja siinä on:

  • korostettu reittiviiva, jossa on näkyvyyttä parantava valkoinen reunus
  • animoitu kameran sijainnin osoitin
  • alku- (vihreä) ja loppumerkki (punainen)
  • valinnaiset 3D-rakennukset kaupunkialueilla

4. Kuvien tallennus ja videon koodaus

Puppeteer tallentaa jokaisen kuvan PNG-kuvakaappauksena, minkä jälkeen koodaamme ne ffmpegillä WebM-videoksi VP9-koodekilla:

1
2
3
ffmpeg -framerate 30 -i frame_%05d.png \
  -c:v libvpx-vp9 -crf 20 -b:v 0 \
  route.webm

Tekninen arkkitehtuuri

1
Django App → Celery Task → Node.js Renderer → S3 Storage
  1. Django käynnistää videon luomisen, kun ryhmäajo luodaan tai sitä päivitetään
  2. Celery asettaa tehtävän jonoon asynkronista käsittelyä varten
  3. Node.js-renderöijä ajaa Puppeteeria ja MapLibre GL:ää
  4. ffmpeg koodaa tallennetut kuvat
  5. Video ladataan S3:een ja ryhmäajon tiedot päivitetään

Suorituskyky

ResoluutioKestoRenderöintiaikaTiedostokoko
1280x72015 s60–90 s2–4 Mt
1920x108015 s90–120 s4–8 Mt

Tuotannossa käytämme Docker-kontteja ohjelmistorenderöinnillä (SwiftShader), jotta emme ole riippuvaisia näytönohjaimesta:

1
2
--use-angle=swiftshader
--enable-unsafe-swiftshader

Lisäämämme ominaisuudet

  • Mukautettavat videon mitat: neliömuoto sosiaalisessa mediassa jakamista varten
  • Logon vesileima: brändää videosi organisaatiosi logolla
  • Kameran kallistus ja zoomaus: säädä katselukulmaa ja korkeutta
  • Reittiviivan tyyli: omat värit ja viivan leveydet

Django-integraatio

Sovelluskoodissa videon luominen on näin yksinkertaista:

1
2
party = Party.objects.get(uid="...")
party.generate_video(width=1080, height=1080, duration=10)

Videon URL päivittyy automaattisesti, kun renderöinti valmistuu:

1
2
3
4
5
{% if party.video_url %}
<video controls>
  <source src="{{ party.video_full_url }}" type="video/webm">
</video>
{% endif %}

Mitä seuraavaksi

Tutkimme useita parannuksia:

  • Reaaliaikainen esikatselu: renderöinti suoraan, kun käyttäjä piirtää reittiä
  • Useita kamerakulmia: sivukuvia ja kuvia suoraan ylhäältä
  • Säätiedot kartalla: ennustetut olosuhteet reitin varrella
  • Korkeusprofiili: nousujen ja laskujen havainnollistaminen videossa

Reittien lentovideoista on tullut yksi suosituimmista ominaisuuksistamme, ja ne auttavat pyöräilijöitä tekemään perusteltuja päätöksiä siitä, mihin ajoihin liittyä. Nykyaikaisten verkkoteknologioiden yhdistelmä muuttaa kalliin tuotantotyön automaattiseksi palveluksi, joka toimii tarpeen mukaan.


Haluatko kokeilla? Luo ryhmäajo, niin reittivideosi luodaan automaattisesti!