Emulasi visual pita analog seperti VHS memerlukan manipulasi sinyal pada domain frekuensi dan pemindaian baris (scanline), bukan sekadar color grading sederhana. Proyek open-source seperti ntsc-rs membuktikan bahwa simulasi akurat terhadap degradasi sinyal komposit, pergeseran chroma (I/Q), dan noise head switching menuntut komputasi intensif per frame. Dalam mendesain platform video berbasis efek ini, muncul keputusan arsitektural krusial: menjalankan pipeline pemrosesan sinyal menggunakan Rust native di backend atau mengeksekusinya di sisi klien melalui WebAssembly (Wasm) dan WebGL/WebGPU.
Pipeline Pemrosesan Sinyal NTSC/VHS
Efek VHS berbasis emulasi sinyal bekerja dengan mengonversi frame digital RGB ke domain analog komposit dan merekonstruksinya kembali:
- RGB ke YIQ: Frame dikonversi ke ruang warna luma (Y) dan in-phase/quadrature (I/Q).
- Modulasi Komposit: Komponen I dan Q dimodulasi ke subcarrier frekuensi tinggi pada fase tertentu per baris scan.
- Penyaringan & Degradasi Pita: Filter low-pass (IIR/FIR) diterapkan pada sinyal untuk memotong bandwidth chroma secara drastis, ditambah saturasi tape, dropouts, dan phase jitter.
- Demodulasi & Rekonstruksi RGB: Sinyal komposit dipisahkan kembali menjadi luma dan chroma menggunakan comb filter, lalu dikonversi kembali ke RGB.
Karena operasi filter IIR bergantung pada sampel baris sebelumnya dalam domain waktu 1D horizontal, pemrosesan ini membebani pipeline per-pixel secara ketat dan sulit diparalelkan secara penuh seperti fragment shader murni.
Arsitektur 1: Backend Rust Native (FFmpeg Filter / Microservice)
Pada pendekatan backend, pemrosesan video dilakukan sebagai proses batch atau stream transcoding. Rust native diintegrasikan langsung ke dalam pipeline video, baik melalui C ABI sebagai custom filter FFmpeg (libavfilter) atau microservice berbasis gRPC.
Kelebihan
- Akses Penuh ke Instruksi SIMD & Threading: Rust native memanfaatkan target CPU server secara optimal (AVX2, AVX-512, atau NEON) dan multi-threading tanpa batas via pustaka seperti
rayon. - Dukungan Enkoder Hardware Terpadu: Integrasi langsung dengan NVENC, VAAPI, atau SVT-AV1 tanpa memindahkan frame mentah (raw pixel buffer) keluar dari memori sistem host.
- Deterministik: Output video seragam di semua perangkat pengguna tanpa terpengaruh variasi implementasi driver GPU lokal.
Kelemahan
- Biaya Komputasi Server: Setiap detik video membebani CPU/GPU server. Emulasi sinyal NTSC pada resolusi 1080p60 membutuhkan kalkulasi matriks konstan yang menaikkan utilisasi core server.
- Biaya Egress dan Storage: Video hasil render harus disimpan dan dialirkan ulang (egress bandwidth) ke klien, menambah biaya operasional infrastruktur.
Arsitektur 2: Client-Side Execution via WebAssembly & WebGL
Pendekatan Wasm memindahkan seluruh beban komputasi emulasi sinyal ke browser pengguna. Core pipeline Rust dikompilasi ke target wasm32-unknown-unknown dan dipanggil dari JavaScript menggunakan wasm-bindgen.
Kelebihan
- Zero Compute Cost di Server: Server hanya berfungsi sebagai penyedia asset statis (binary Wasm dan file HTML/JS). Beban CPU sepenuhnya diserap oleh perangkat klien.
- Egress Ringan: Server hanya mengirimkan payload video sumber asli satu kali; hasil render langsung diekspor lokal di browser melalui WebCodecs API atau Canvas capture.
- Interaktivitas Real-Time Rendah: Pengguna dapat memanipulasi parameter efek (seperti tracking noise atau tape drop) tanpa latensi jaringan bolak-balik (round-trip).
Kelemahan & Batasan Teknis
- Overhead Boundary JS-Wasm: Memindahkan frame mentah (misal: RGBA 1080p = ~8.3 MB per frame) bolak-balik antara JavaScript heap dan linear memory Wasm menimbulkan latency dan alokasi memori tinggi jika tidak dikelola dengan raw pointer sharing.
- Keterbatasan Wasm SIMD: Wasm SIMD (128-bit) memiliki kapabilitas instruksi yang lebih terbatas dibanding AVX2/AVX-512 native.
- Fragmentasi Performa Klien: Perangkat mobile low-end akan mengalami frame dropping parah pada pemrosesan 60 FPS real-time.
Strategi Basis Kode Tunggal (Core Logic Sharing)
Untuk menghindari redundansi pemeliharaan logika, gunakan arsitektur modular di mana algoritma modulasi NTSC berada dalam crate Rust independen (misalnya vhs-core) tanpa dependensi IO runtime.
// vhs-core/src/lib.rs
#![no_std]
extern crate alloc;
use alloc::vec::Vec;
pub struct NtscFilterConfig {
pub luma_bandwidth: f32,
pub chroma_drift: f32,
pub noise_intensity: f32,
}
// Logika murni: tidak peduli apakah dipanggil dari FFmpeg native atau Wasm
pub fn process_scanline(
row_yiq: &mut [(f32, f32, f32)],
subcarrier_phase: f32,
config: &NtscFilterConfig
) {
for (i, pixel) in row_yiq.iter_mut().enumerate() {
let phase = subcarrier_phase + (i as f32 * 0.25);
// Emulasi attenuasi subcarrier chroma analog
pixel.1 *= config.chroma_drift * phase.cos();
pixel.2 *= config.chroma_drift * phase.sin();
}
}
Crate ini kemudian dibungkus oleh dua adapter terpisah:
vhs-native-cli: Menautkanvhs-coreke pipeline FFmpeg native menggunakan I/O stream berkecepatan tinggi dan multi-threading Rayon.vhs-wasm: Menyediakan interface memory pointer langsung agar WebGL/Canvas dapat membaca linear memory Wasm via buffer zero-copy.
// vhs-wasm/src/lib.rs
use wasm_bindgen::prelude::*;
use vhs_core::{process_scanline, NtscFilterConfig};
#[wasm_bindgen]
pub struct WasmVideoProcessor {
buffer: Vec<f32>,
config: NtscFilterConfig,
}
#[wasm_bindgen]
impl WasmVideoProcessor {
#[wasm_bindgen(constructor)]
pub fn new(capacity: usize) -> Self {
Self {
buffer: vec![0.0; capacity],
config: NtscFilterConfig {
luma_bandwidth: 0.8,
chroma_drift: 1.1,
noise_intensity: 0.05,
},
}
}
// Mengembalikan raw pointer ke buffer linear Wasm untuk zero-copy WebGL texture update
pub fn buffer_ptr(&self) -> *const f32 {
self.buffer.as_ptr()
}
pub fn process_frame(&mut self, width: usize, height: usize) {
// Implementasi modifikasi buffer in-place
}
}
Estimasi Model Biaya: Pemrosesan 1.000 Jam Video
Pertimbangkan volume pemrosesan 1.000 jam video beresolusi 1080p pada bitrate 5 Mbps (total ukuran file masukan sekitar 2,25 TB):
| Komponen Biaya | Backend Rust Native (Cloud c6i.2xlarge) | Client-Side WebAssembly (S3 + CDN) |
|---|---|---|
| Compute Server | ~$170 (Estimasi ~1.000 core-hours processing) | $0 (Ditanggung CPU klien) |
| Storage (Output) | ~$50 / bulan (2,25 TB S3 Standard) | $0 (Disimpan lokal oleh klien) |
| Egress Bandwidth | ~$180 (Pengiriman hasil render 2,25 TB) | ~$190 (Hanya pengiriman source video + Wasm binary) |
| Total Estimasi | ~$400 | ~$190 |
Meskipun arsitektur Wasm menghemat biaya komputasi hingga 100% dan memangkas separuh total pengeluaran, trade-off muncul pada performa eksekusi klien yang tidak homogen.
Panduan Pemilihan Arsitektur
Terapkan pendekatan berikut berdasarkan use case dan kapabilitas hardware:
- Pilih Client-Side WebAssembly jika: Aplikasi berupa browser-based video editor non-linear (NLE), preview interaktif parameter real-time, atau SaaS berbasis pengguna mandiri di mana hardware target adalah desktop modern dengan dukungan WebCodecs dan WebGL 2.0.
- Pilih Backend Rust Native jika: Video harus diekspor dalam format master berkualitas tinggi, pipeline batch terjadwal, video berdurasi panjang (>30 menit per file), atau melayani pengguna mobile dengan keterbatasan konsumsi baterai dan thread CPU.
- Arsitektur Hibrida (Rekomendasi Terbaik): Jalankan Wasm pada canvas resolusi rendah (360p/480p) untuk preview interaktif real-time tanpa latensi di sisi klien, lalu kirim file konfigurasi parameter JSON ke worker Rust native di backend untuk rendering akhir resolusi penuh (1080p/4K).
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!