I implemented CMAF through a self-built nginx server with ffmpeg, but I encountered some technical bottlenecks. My latency always remains at 3 seconds and cannot be further reduced. Additionally, I'm unable to successfully implement chunked transfer.
Briefly describe my environment, I use OBS to push the live stream to the server, then transcode it on the server, and finally push the content to users through CDN.
Here is some of my code
ffmpeg:
sudo ffmpeg -i rtmp://127.0.0.1:1935/live/stream -loglevel 40 -c copy -sc_threshold 0 -g 60 -bf 0 -map 0 -f dash -strict experimental -use_timeline 1 -use_template 1 -seg_duration 1 -window_size 5 -adaptation_sets "id=0,streams=v id=1,streams=a" -streaming 1 -dash_segment_type mp4 -utc_timing_url "http://time.akamai.com/?iso" -movflags frag_keyframe+empty_moov+default_base_moof -ldash 1 -hls_playlist 1 -master_m3u8_publish_rate 1 -remove_at_exit 1 /var/www/html/live/manifest.mpd
nignx config:
server_name myserver.com;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';
root /var/www/html;
index index.html index.nginx-debian.html;
location / {
chunked_transfer_encoding on;
}
html player
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>streaming test</title>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
<style>
body {
margin: 0;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #000;
}
#video {
max-width: 100%;
max-height: 100vh;
}
</style>
</head>
<body>
<video id="video" controls></video>
<script>
const video = document.getElementById('video');
const hlsSrc = '/live/master.m3u8'; // Replace with your HLS stream URL
const dashSrc = '/live/stream.mpd'; // Replace with your DASH stream URL
function isHlsSupported() {
return Hls.isSupported() || video.canPlayType('application/vnd.apple.mpegurl');
}
function isDashSupported() {
return !!window.MediaSource && !!MediaSource.isTypeSupported('video/mp4; codecs="avc1.4d401e,mp4a.40.2"');
}
if (isHlsSupported()) {
// Use HLS for playback
const hls = new Hls({
lowLatencyMode: true,// Enable low-latency mode
liveSyncDurationCount: 1, // Number of segments used to sync live stream
liveMaxLatencyDurationCount: 2,// Number of segments used to calculate the latency
maxBufferLength: 2,// Max buffer length in seconds
maxBufferSize: 1000 * 1000 * 100,// Max buffer size in bytes
liveBackBufferLength: 0// Max back buffer length in seconds (0 means back buffer disabled)
});
hls.loadSource(hlsSrc);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play();
});
} else if (isDashSupported()) {
// Use DASH for playback
const player = dashjs.MediaPlayer().create();
player.initialize(video, dashSrc, true);
player.updateSettings({
streaming: {
lowLatencyEnabled: true, // Enable low-latency mode
liveDelay: 1, // Set live delay in seconds, equal to 3 times the segment duration
liveCatchUpPlaybackRate: 1.2, // Playback rate for catching up when behind the live edge
liveCatchUpMinDrift: 0.5, // Minimum drift from live edge before initiating catch-up (in seconds)
bufferTimeAtTopQuality: 3, // Maximum buffer length in seconds
bufferToKeep: 0, // Duration of the back buffer in seconds (disable back buffer)
}
});
} else {
console.error('Neither HLS nor DASH playback is supported in this browser.');
}
</script>
</body>
</html>
I hope to reduce the latency to 1 second.