Bạn đã bao giờ ước có thể xem trước một tuyến đường đạp xe trước khi đạp chưa? Chúng tôi đã xây dựng một hệ thống tự động tạo video flyover đẹp mắt cho mọi tuyến đường Party Onbici, cho người đi xe đạp xem trước điện ảnh về những gì họ có thể mong đợi trong chuyến đi.

Thách thức

Khi tổ chức hoặc tham gia một sự kiện đạp xe, việc hiểu tuyến đường là rất quan trọng. Bản đồ tĩnh hữu ích, nhưng chúng không truyền tải được trải nghiệm thực sự đạp tuyến đường. Chúng tôi muốn cho người dùng một cách để “bay qua” tuyến đường ảo trước khi quyết định tham gia.

Giải pháp của chúng tôi: Headless Video Rendering

Chúng tôi đã xây dựng một dịch vụ Node.js chạy trình duyệt headless Chrome sử dụng Puppeteer, render tuyến đường trên bản đồ MapLibre GL tương tác, và chụp các frame khi camera ảo bay dọc theo đường đi. Đây là cách nó hoạt động:

1. Nội suy tuyến đường

Một tuyến đường đạp xe có thể có hàng nghìn điểm tọa độ. Để tạo video mượt mà ở 30 FPS trong 15 giây, chúng tôi cần đúng 450 frame. Chúng tôi sử dụng nội suy dựa trên khoảng cách để lấy mẫu tuyến đường đều:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Tính khoảng cách tích lũy sử dụng công thức 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);
}

// Lấy mẫu tại đúng totalFrames điểm
for (let frame = 0; frame < totalFrames; frame++) {
  const targetDist = (frame / (totalFrames - 1)) * totalDistance;
  // Nội suy vị trí tại khoảng cách này...
}

2. Animation camera với hướng mượt mà

Đơn giản chỉ hướng camera theo hướng di chuyển tạo ra chuyển động giật trên các tuyến đường quanh co. Chúng tôi làm mượt hướng camera bằng trung bình động 12 frame, với xử lý đặc biệt cho vòng quay 360°/0°:

1
2
3
4
5
6
7
// Sử dụng các thành phần sin/cos cho trung bình vòng tròn
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. MapLibre GL Rendering

Tuyến đường được render trên lớp nền đẹp của Stadia Maps với:

  • Đường tuyến đường được tô sáng với viền trắng để dễ nhìn
  • Chỉ báo vị trí camera có animation
  • Điểm đánh dấu bắt đầu (xanh lá) và kết thúc (đỏ)
  • Tùy chọn extrusion tòa nhà 3D cho khu vực đô thị

4. Chụp frame và mã hóa video

Puppeteer chụp mỗi frame dưới dạng ảnh chụp màn hình PNG, sau đó chúng tôi sử dụng ffmpeg để mã hóa chúng thành video WebM với codec VP9:

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

Kiến trúc kỹ thuật

1
Django App → Celery Task → Node.js Renderer → S3 Storage
  1. Django kích hoạt tạo video khi party được tạo hoặc cập nhật
  2. Celery xếp hàng task để xử lý bất đồng bộ
  3. Node.js renderer chạy Puppeteer với MapLibre GL
  4. ffmpeg mã hóa các frame đã chụp
  5. Video được upload lên S3 và bản ghi party được cập nhật

Cân nhắc về hiệu suất

Độ phân giảiThời lượngThời gian renderKích thước file
1280x72015s60-90s2-4 MB
1920x108015s90-120s4-8 MB

Trong production, chúng tôi sử dụng Docker containers với software rendering (SwiftShader) để tránh phụ thuộc GPU:

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

Các tính năng chúng tôi đã thêm

  • Kích thước video tùy chỉnh - Định dạng vuông để chia sẻ trên mạng xã hội
  • Watermark logo - Đánh dấu video của bạn với logo tổ chức
  • Góc nghiêng và zoom camera - Điều chỉnh góc nhìn và độ cao
  • Kiểu đường tuyến đường - Màu sắc và độ rộng tùy chỉnh

Tích hợp Django

Từ code ứng dụng, tạo video đơn giản như sau:

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

URL video được tự động cập nhật khi rendering hoàn tất:

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

Tiếp theo là gì

Chúng tôi đang khám phá một số cải tiến:

  • Xem trước thời gian thực - Rendering trực tiếp khi người dùng vẽ tuyến đường
  • Nhiều góc camera - Góc nhìn bên, góc nhìn từ trên
  • Overlay thời tiết - Hiển thị điều kiện dự báo dọc theo tuyến đường
  • Hồ sơ độ cao - Hiển thị các đoạn leo và xuống trong video

Video flyover tuyến đường đã trở thành một trong những tính năng phổ biến nhất của chúng tôi, giúp người đi xe đạp đưa ra quyết định có thông tin về chuyến đi nào sẽ tham gia. Sự kết hợp của các công nghệ web hiện đại biến những gì sẽ là một tác vụ sản xuất đắt đỏ thành một dịch vụ tự động, theo yêu cầu.


Muốn thử? Tạo một party và video tuyến đường của bạn sẽ được tạo tự động!