FFmpeg Hardware Multi-Bitrate Live Transcoding
This article explains how to efficiently transcode a single live input stream into multiple output bitrates using a single, hardware-accelerated pipeline in FFmpeg. By leveraging GPU acceleration (such as NVIDIA NVENC/NVDEC) and FFmpeg’s hardware filter graph, you can minimize CPU usage, eliminate system memory bottlenecks, and optimize delivery for adaptive bitrate (ABR) live streaming.
The Hardware-Accelerated Pipeline Concept
To achieve maximum performance, the entire transcoding pipeline—decoding, scaling, and encoding—must remain inside the GPU’s video memory (VRAM). Copying video frames back and forth between system RAM (CPU) and VRAM (GPU) introduces latency and consumes significant system bandwidth.
By using NVIDIA’s CUDA-accelerated tools within FFmpeg, we can ingest a stream, decode it to VRAM, split and scale it to various resolutions on the GPU, and encode those streams simultaneously using NVENC.
The FFmpeg Command
Below is a production-ready FFmpeg command that takes a single 1080p live input and transcodes it into three distinct resolutions (1080p, 720p, and 480p) using NVIDIA GPU acceleration, outputting an HLS directory structure with a master playlist.
ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i rtmp://localhost/live/input \
-filter_complex "[0:v]split=3[v1][v2][v3]; \
[v1]scale_cuda=1920:1080[out1]; \
[v2]scale_cuda=1280:720[out2]; \
[v3]scale_cuda=854:480[out3]" \
-map "[out1]" -c:v:0 h264_nvenc -b:v:0 5000k -g 50 -keyint_min 50 -sc_threshold 0 \
-map "[out2]" -c:v:1 h264_nvenc -b:v:1 3000k -g 50 -keyint_min 50 -sc_threshold 0 \
-map "[out3]" -c:v:2 h264_nvenc -b:v:2 1400k -g 50 -keyint_min 50 -sc_threshold 0 \
-map 0:a -c:a:0 aac -b:a:0 128k \
-map 0:a -c:a:1 aac -b:a:1 128k \
-map 0:a -c:a:2 aac -b:a:2 96k \
-f hls -hls_time 2 -hls_playlist_type event \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" /var/www/html/live/stream_%v.m3u8How the Pipeline Works
1. GPU Decoding and Memory Management
-hwaccel cuda: Tells FFmpeg to use CUDA to hardware-accelerate the decoding process of the input stream.-hwaccel_output_format cuda: Forces the decoded frames to remain inside GPU memory (CUDA frames) rather than downloading them back to system memory.
2. Hardware-Accelerated Filtering
[0:v]split=3[v1][v2][v3]: This filter splits the single GPU memory pointer of the decoded video stream into three parallel pathways inside VRAM.scale_cuda=W:H: Instead of the standard CPU-basedscalefilter,scale_cudaresizes the frames directly inside the GPU cores. This avoids bringing the video frames to the CPU for scaling.
3. Dedicated Hardware Encoding
-c:v h264_nvenc: Uses the physical NVIDIA NVENC ASIC on the graphics card to encode the streams.-g 50 -keyint_min 50 -sc_threshold 0: These settings are crucial for Adaptive Bitrate (ABR) streaming. They force a strict Group of Pictures (GOP) size of 50 frames (2 seconds at 25 FPS) and disable scene change detection. This ensures that keyframes line up perfectly across all three output resolutions, allowing players to transition smoothly between qualities.
4. Audio Mapping and HLS Packager
- The audio is copied and encoded into different bitrates using the
CPU-based
aacencoder (since audio encoding consumes negligible system resources). -f hls: Packets are packaged on-the-fly into HTTP Live Streaming (HLS) segments.-var_stream_map: Maps the respective scaled video outputs to their corresponding audio streams, outputting a consolidatedmaster.m3u8file for client playback.