The Problem
When I started building Akture, the core challenge was deceptively simple to state: take a live RTSP stream from a sports court camera, process it in real time, and deliver it to users with minimal latency. In practice, doing this across 11 concurrent venues while keeping infrastructure costs manageable is a very different problem.
Architecture Overview
The pipeline has three main stages:
- Ingestion — RTSP streams are pulled from venue cameras using FFmpeg, which handles codec negotiation and buffering.
- Processing — Frames are processed in background workers (Spring Boot async tasks) for trimming, combining, and transcoding.
- Delivery — Processed video is stored in AWS S3 and served via CloudFront for low-latency global delivery.
Key Technical Decisions
Why FFmpeg over dedicated media servers?
FFmpeg gave us the most flexibility for processing. We needed to trim, combine, and transcode on demand — operations that purpose-built streaming servers like Wowza don't handle as cleanly without significant cost.
Background processing with Spring Boot
Each venue stream runs in its own async context. Using @Async with a configured ThreadPoolTaskExecutor gave us controlled concurrency without spinning up separate services for each stream.
S3 + CloudFront for delivery
Rather than streaming directly from EC2, we write processed segments to S3 and distribute via CloudFront. This decouples processing from delivery, reduces egress costs, and gives us automatic geographic distribution.
What I'd Do Differently
With hindsight, I'd introduce a message queue (Kafka or SQS) between ingestion and processing earlier. As venue count grew, the tight coupling created backpressure issues that required retrofitting an async queue mid-build — always more painful than designing for it upfront.
Results
The pipeline now handles ~2TB/hr across all venues, with a ~80% user-to-purchase conversion on the resulting content — validating the product hypothesis that high-quality, on-demand sports replay drives direct revenue.