Czy kiedykolwiek marzyłeś o tym, żeby zobaczyć trasę rowerową zanim ją przejedziesz? Zbudowaliśmy zautomatyzowany system, który generuje piękne wideo przelotów dla każdej trasy Party Onbici, dając rowerzystom kinowy podgląd tego, czego mogą się spodziewać w podróży.

Wyzwanie

Podczas organizowania lub dołączania do wydarzenia rowerowego, zrozumienie trasy jest kluczowe. Statyczne mapy są pomocne, ale nie przekazują doświadczenia faktycznego przejazdu trasą. Chcieliśmy dać użytkownikom sposób na wirtualny “przelot” przez trasę przed podjęciem decyzji o jeździe.

Nasze rozwiązanie: Headless renderowanie wideo

Zbudowaliśmy usługę Node.js, która uruchamia przeglądarkę headless Chrome przy użyciu Puppeteer, renderuje trasę na interaktywnej mapie MapLibre GL i przechwytuje klatki, gdy wirtualna kamera leci wzdłuż ścieżki. Oto jak to działa:

1. Interpolacja trasy

Trasa rowerowa może mieć tysiące punktów współrzędnych. Aby stworzyć płynne wideo przy 30 FPS przez 15 sekund, potrzebujemy dokładnie 450 klatek. Używamy interpolacji opartej na dystansie, aby równomiernie próbkować trasę:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Oblicz skumulowane odległości używając wzoru Haversine
const distances = [0];
for (let i = 1; i < coordinates.length; i++) {
  const dist = haversineDistance(coordinates[i-1], coordinates[i]);
  totalDistance += dist;
  distances.push(totalDistance);
}

// Próbkuj w dokładnie totalFrames punktach
for (let frame = 0; frame < totalFrames; frame++) {
  const targetDist = (frame / (totalFrames - 1)) * totalDistance;
  // Interpoluj pozycję przy tym dystansie...
}

2. Animacja kamery z wygładzonym kursem

Proste kierowanie kamery w kierunku jazdy tworzy szarpany ruch na krętych trasach. Wygładzamy kurs kamery używając średniej ruchomej z 12 klatek, ze specjalną obsługą przejścia 360°/0°:

1
2
3
4
5
6
7
// Użyj komponentów sin/cos do uśredniania kołowego
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. Renderowanie MapLibre GL

Trasa jest renderowana na pięknej warstwie bazowej Stadia Maps z:

  • Podświetloną linią trasy z białym obrysem dla widoczności
  • Animowanym wskaźnikiem pozycji kamery
  • Markerami startu (zielony) i mety (czerwony)
  • Opcjonalnymi ekstrudowanymi budynkami 3D dla obszarów miejskich

4. Przechwytywanie klatek i kodowanie wideo

Puppeteer przechwytuje każdą klatkę jako zrzut ekranu PNG, następnie używamy ffmpeg do zakodowania ich w wideo WebM z kodekiem VP9:

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

Architektura techniczna

1
Aplikacja Django → Zadanie Celery → Renderer Node.js → Przechowywanie S3
  1. Django uruchamia generowanie wideo gdy party jest tworzony lub aktualizowany
  2. Celery kolejkuje zadanie do przetwarzania asynchronicznego
  3. Renderer Node.js uruchamia Puppeteer z MapLibre GL
  4. ffmpeg koduje przechwycone klatki
  5. Wideo jest przesyłane do S3 i rekord party jest aktualizowany

Rozważania dotyczące wydajności

RozdzielczośćCzas trwaniaCzas renderowaniaRozmiar pliku
1280x72015s60-90s2-4 MB
1920x108015s90-120s4-8 MB

W produkcji używamy kontenerów Docker z renderowaniem programowym (SwiftShader), aby uniknąć zależności od GPU:

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

Funkcje, które dodaliśmy

  • Konfigurowalne wymiary wideo - Kwadratowy format do udostępniania w mediach społecznościowych
  • Znak wodny z logo - Oznacz swoje wideo logo organizacji
  • Kąt i przybliżenie kamery - Dostosuj kąt widzenia i wysokość
  • Stylizacja linii trasy - Niestandardowe kolory i szerokości

Integracja z Django

Z kodu aplikacji generowanie wideo jest tak proste jak:

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

URL wideo jest automatycznie aktualizowany po zakończeniu renderowania:

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

Co dalej

Badamy kilka ulepszeń:

  • Podgląd w czasie rzeczywistym - Renderowanie na żywo podczas rysowania tras
  • Wiele kątów kamery - Widoki z boku, z góry
  • Nakładka pogodowa - Pokaż prognozowane warunki wzdłuż trasy
  • Profil wysokości - Wizualizuj wspinaczki i zjazdy w wideo

Wideo przelotów tras stały się jedną z naszych najpopularniejszych funkcji, pomagając rowerzystom podejmować świadome decyzje o tym, do których jazd dołączyć. Połączenie nowoczesnych technologii webowych sprawia, że to, co byłoby kosztownym zadaniem produkcyjnym, staje się zautomatyzowaną usługą na żądanie.


Chcesz to wypróbować? Utwórz party a wideo twojej trasy zostanie automatycznie wygenerowane!