A tool for transcoding and uploading videos to a CDN network for HLS video streaming.
- Input: video file (AVI, MKV, MP4, WMV) @ 1080p (or higher) resolution
- Output: video file converted to streamable MP4 video at several bitrates:
- MP4 @
1080p
(~ 1100 kbps bitrate) - MP4 @
720p
(~ 650 kbps bitrate) - MP4 @
480p
(~ 400 kbps bitrate) - MP4 @
360p
(~ 250 kbps bitrate) -> optional - MP4 @
240p
(~ 150 kbps bitrate)
- MP4 @
- Upload: the files are uploaded through to FTP to the target CDN network
The tool uses internally ffmpeg
with the following default parameters for VoD streaming (using libx264-based CPU video encoder + decoder):
1080p (1000-1200kbps)
ffmpeg.exe -i input.mp4 -c:v libx264 -s 1920x1080 -r 30 -g 60 -crf 25 -maxrate 1500k -bufsize 3000k -c:a aac -b:a 192k -y sample-1080p.mp4
720p (600-800 kbps)
ffmpeg.exe -i input.mp4 -c:v libx264 -s 1280x720 -r 30 -g 60 -crf 24 -maxrate 1000k -bufsize 2000k -c:a aac -b:a 128k -y sample-720p.mp4
480p (350-450 kbps)
ffmpeg.exe -i input.mp4 -c:v libx264 -s 854x480 -r 25 -g 50 -crf 23 -maxrate 600k -bufsize 1200k -c:a aac -b:a 96k -y sample-480p.mp4
360p (200-300 kbps)
ffmpeg.exe -i input.mp4 -c:v libx264 -s 640x360 -r 24 -g 48 -crf 24 -maxrate 400k -bufsize 800k -c:a aac -b:a 64k -y sample-360p.mp4
240p (100-200 kbps)
ffmpeg.exe -i input.mp4 -c:v libx264 -s 426x240 -r 15 -g 30 -crf 25 -maxrate 250k -bufsize 500k -c:a aac -b:a 48k -y sample-240p.mp4
Notes:
- The above commands use CPU-based transcoding (using the
libx264
CPU encoder) --> it is slow - Frames per second (fps): 30 fps for hi-res streams; 15-25 fps for low-res streams
- The audio is also resampled: 128-192 kbps for his-res streams; 48-96 kbps for low-res streams
Links:
- https://slhck.info/video/2017/03/01/rate-control.html
- https://developers.google.com/media/vp9/settings/vod
These are the ffmpeg
settings to achieve similar results (for less encoding time), using the NVENC hardware accelerated video encoding (NVidia GPU, decoder h264_cuvid
, encoder h264_nvenc
):
1080p (1000-1200kbps)
ffmpeg.exe -c:v h264_cuvid -resize 1920x1080 -i input.mp4 -c:v h264_nvenc -r 30 -g 60 -rc vbr -cq 34 -c:a aac -b:a 192k -y sample-1080p.mp4
720p (600-800 kbps)
ffmpeg.exe -c:v h264_cuvid -resize 1280x720 -i input.mp4 -c:v h264_nvenc -r 30 -g 60 -rc vbr -multipass fullres -cq 34 -c:a aac -b:a 128k -y sample-720p.mp4
480p (350-450 kbps)
ffmpeg.exe -c:v h264_cuvid -resize 854x480 -i input.mp4 -c:v h264_nvenc -r 25 -g 50 -rc vbr -multipass fullres -cq 32 -c:a aac -b:a 96k -y sample-480p.mp4
360p (200-300 kbps)
ffmpeg.exe -c:v h264_cuvid -resize 854x480 -i input.mp4 -c:v h264_nvenc -r 24 -g 48 -rc vbr -multipass fullres -cq 37 -c:a aac -b:a 64k -y sample-360p.mp4
240p (100-200 kbps)
ffmpeg.exe -c:v h264_cuvid -resize 426x240 -i input.mp4 -c:v h264_nvenc -r 15 -g 30 -rc vbr -multipass fullres -cq 32 -c:a aac -b:a 48k -y sample-240p.mp4
Notes:
- Multipass for 1080p is intentionally swiched off, because it slows down the transcoding speed by 45%, with no visible improvement
- The above commands are designed to run on Windows machine, with NVidia graphics card, which supports hardware video encoding & decoding
- Require the latest NVidia drivers, installed in your Windows machine
- Require the latest
ffmpeg
for Windows (from Nov 2020 or later) - Choose the encoder / decoder GPU by:
-gpu 0
/-gpu 1
/-gpu 2
... (if you have multiple GPUs)
Tested with ffmpeg version 2020-11-29-git-f194cedfe6-full_build-www.gyan.dev
:
Links:
- https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/
- https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/
- https://gist.github.com/nakov/63375816c9d3201c499b15b110ca6136
This list describes the performance of NVidia video cards for video encoding (NVENC / NVDEC):
NVidia drivers apply an internal software-based limitation on the maximum number of NVENC video encoding sessions (how many files can be encoded simultaneously with ffmpeg
). This software limitation aritificially reduces the performance of parallel video encoding. NVidia wants you to purchase more expensive video card if you want to encode more videos in parallel. The card's hardware is capable to encode more videos in parallel, but NVidia drivers artificially limit this.
To remove the NVENC sessions restriction, you can use the NVENC patch tool for the NVidia video drivers (on your own risk): https://github.com/keylase/nvidia-patch/tree/master/win.
If you have Intel video card (GPU), which is usually built in most Intel processors, you can use it for hardware-accelerated video transcoding (with Intel Quick Sync). Example of using Intel GPU transcoder, with variable bitrate, limited by video quality (recommended). It uses h264_qsv
as decoder and h264_qsv
as encoder:
ffmpeg.exe -c:v h264_qsv -i input.mp4 -c:v h264_qsv -s 426x240 -r 24 -global_quality 28 -look_ahead 1 -c:a aac -b:a 48k -y output-240p.mp4
CPU-based decoder + Intel GPU-based encoder:
ffmpeg.exe -i input.mp4 -c:v h264_qsv -s 426x240 -r 24 -global_quality 28 -look_ahead 1 -c:a aac -b:a 48k -y output-240p.mp4
Intel GPU encoder + GPU decoder (videos size is limited by bitrate):
ffmpeg.exe -c:v h264_qsv -i input.mp4 -c:v h264_qsv -s 426x240 -r 24 -g 48 -b:v 200k -maxrate 250k -bufsize 500k -c:a aac -b:a 48k -y output-240p.mp4
This example demonstrates how to combine 2 NVidia GPUs + 1 Intel GPU + 1 Intel CPU, which are available on a single machine with Intel CPU + built-in Intel GPU + 2 additional NVidia video cards. These are the transcoding seettings for the CDN Video Uploader for 1080p, 720p, 480p and 240p:
1080p | ffmpeg.exe -c:v h264_cuvid -gpu 0 -resize 1920x1080 -i {input} -c:v h264_nvenc -gpu 0 -r 30 -g 60 -rc vbr -cq 34 -c:a aac -b:a 192k -y {output}
720p | ffmpeg.exe -c:v h264_cuvid -gpu 1 -resize 1280x720 -i {input} -c:v h264_nvenc -gpu 1 -r 30 -g 60 -rc vbr -multipass fullres -cq 34 -c:a aac -b:a 128k -y {output}
480p | ffmpeg.exe -c:v h264_cuvid -gpu 0 -resize 854x480 -i {input} -c:v h264_nvenc -gpu 0 -r 25 -g 50 -rc vbr -multipass fullres -cq 32 -c:a aac -b:a 96k -y {output}
240p | ffmpeg.exe -i {input} -c:v h264_qsv -s 426x240 -r 15 -global_quality 28 -look_ahead 1 -c:a aac -b:a 48k -y {output}
In the above setup we assume we have NVidia card with 2 GPUs + Intel GPU (in the built-in video card):
- 1080p and 480p videos are decoded and encoded on NVidia GPU 0
- 720p video is decoded and encoded on NVidia GPU 1
- 240p video is decoded on CPU and encoded on Intel GPU Thus the time for the entire transcoding process is ~ 3 times faster than when we use only one GPU.
The tool generates HLS adaptable bitrate stream, using the standard API from UCDN. Its generates m3u8
HLS playlist URL like this:
https://11461-1.b.cdn12.com/hls/videos-2024/sample-,240,360,720,1080,p.mp4/urlset/master.m3u8
The above playlist combines the following transcoded mp4
streamable video files (already uploaded at the CDN):
https://11461-1.b.cdn12.com/videos-2024/sample-240p.mp4
https://11461-1.b.cdn12.com/videos-2024/sample-360p.mp4
https://11461-1.b.cdn12.com/videos-2024/sample-720p.mp4
https://11461-1.b.cdn12.com/videos-2024/sample-1080p.mp4
App settings are used to configure:
- Save FTP credentials (yes / no)
- How many transcoding sessions to run in parallel (depends on your hardware, when you have 2 GPUs, use 2 sessions)
- Video transcoding profiles --> configure the resolutions for transcoding (typically 1080p, 720p, 480p and 240p) and the respective
ffmpeg
commands with the transcoding parameters and hardware acceleration parameters - CDN patterns for generating HLS playlists in
m3u8
format. Different folders at the FTP server can be mapped to different CDN hostnames. The exact output URL formats is highly dependent on the specific CDN API for transmuxing a set ofmp4
files tom3u8
playlist.
- Windows OS with .NET Framework
ffmpeg
, locally installed and configured in the system PATH- NVidia graphics card + latest drivers (if you use hardware encoding)
- C#, Windows Forms, .NET Framework, Visual Studio
Behind the Windows Forms based UI the project uses a queue of jobs, which hold a sequence of actions.
- Both jobs and actions are designed to run asynchronously and implement a single interface
ExecutableAction
, which defines basic operations (like start, update state and stop), some events (state changed, error occured) and execution state (not started, running, completed suuccessfully, failed, canceled). - Jobs hold a sequence of actions (like "transcode to 720p", "FTP upload transcoded file" and others).
- Jobs wait in the "active jobs" queue, then execute and when they finish (succeed, fail or cancel), they are moved to another queue "completed jobs".
- Actions hold a single task to be executed, such as "transcode an input file to certain profile (e.g. 720p)" or "upload video file to FTP".
- Actions supported:
TranscodeAction
andUploadAction
- Actions supported:
The jobs scheduler runs asynchronously and activates once per second to do the following:
- Update the state of each job. This causes the jobs to internally update the states of their actions.
- When an action is completed successfully, start the next action in the job.
- When all actions in a job are completed suuccessfully (or certain action is failed or is canceled), move the job to the "completed jobs" queue.
The FTP functionality is based on FluentFTP library.