I wanted to support CMAF to package and support HTTP streams. It supports both MPEG-DASH and HLS protocols.
Environment:
Ubuntu 20.04.6 LTS
Use ffmpeg to create a mp4 using a directory of jpegs
The jpeg files had seconds and nanoseconds in the filename (e.g. 1717013439117358336.jpeg - 1717013439 seconds 117358336 nanoseconds) and had 1440x1080 pixels resolution.
ffmpeg -y -framerate 30 -pattern_type glob -i "/home/cherryshoe/processed/feed/*.jpeg" -s:v 1440x1080 -c:v libx264 -crf 18 -pix_fmt yuv420p videos/feed.mp4
- -y: overrides output files without asking
- -framerate: is calculated by the number of files in the directory divided by the number of seconds covered by the available jpeg files.
- Frame rate can be calculated with the available files in the time period span. Or you can inject as many frames as you want to get the desired framerate (via code to duplicate jpeg files), which is what I did to get 30 frames per second.
- -pattern_type glob: in conjunction with -i option will read a list of input files
- -s:v specifies width x height of output
- -c:v libx264 specifies libx264 video encoding
- -crf 18 is the constant rate factor: For x264 the valid range is 0-51 (default is 23). Consider 18 to be visually lossless or nearly so
- -pxt_fmt yuv420p is the input pixel format
I chose bento4 since it's a mp4 toolkit to support MP4 and DASH/HLS/CMAF media format needs.
1. Created fragmented mp4s with mp4fragment utility:
mp4fragment feed1.mp4 feed1-frag.mp4
2. Use mp4dash to creates a MPEG DASH and HLS output from one or more fragmented MP4 files
mp4dash --hls --use-segment-timeline --force --mpd-name=master.mpd --output-dir ~/TEMP/output feed1-frag.mp4
- --hls to also support HLS (creates m3u8 files)
- --use-segment-timeline (necessary if segment durations vary)
- --force allows output to an existing directory
- --mpd-name=master.mpd (match playlist filename of HLS m3u8)
- --output-dir is where you want the output files to be saved to
This creates an output format like:
- master.m3u8
- master.mpd
- video
- avc1
- iframes.m3u8
- init.mp4
- media.m3u8
- seg-*.m4s
3. Copy the output recursively to a folder where you want to store stream files, e.g. /mnt/streams/feed1
sudo cp -r ~/TEMP/output/* /mnt/streams/feed1
4. Configure nginx. The following can be added to the existing nginx.conf file after standard installation. No extra modules need to be installed other than the standard installation.
Since we want /mnt/streams to be the root folder of any HTTP based streaming streams, the location is configured with "/streams" and the root is configuerd as "/mnt".
# CMAF streaming configuration
server {
listen 8080;
sendfile off;
tcp_nopush on;
aio on;
directio 512;
location /streams {
# Disable cache
add_header 'Cache-Control' 'no-cache';
# CORS setup
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length';
# allow CORS preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
types {
application/dash+xml mpd; # support DASH manifest
application/vnd.apple.mpegurl m3u8; # support HLS manifest
video/mp4 m4s; # support DASH video chunks
}
root /mnt/;
}
}
5. HTML sample code using video.js player - https://videojs.com/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Live streaming</title>
<link href="https://vjs.zencdn.net/8.12.0/video-js.css" rel="stylesheet" />
<script defer src="https://vjs.zencdn.net/8.12.0/video.min.js"></script>
</head>
<body>
<table>
<tr>
<td>
HLS<br>
<video
id="video-1"
class="video-js"
preload="auto"
width="400"
controls
data-setup="{}"
>
<source
src="http://localhost/streams/feed1/master.m3u8"
type="application/x-mpegURL"
/>
</video>
</td>
</tr>
<tr>
<td>
DASH<br>
<video
id="video-2"
class="video-js"
preload="auto"
width="400"
controls
data-setup="{}"
>
<source
src="http://localhost/streams/feed1/master.mpd"
type="application/dash+xml"
/>
</video>
</td>
</tr>
</table>
</body>
</html>