soyersoyer / fmp4streamer

Fmp4streamer streams your V4L2 camera directly to any browser and media player as MP4 (H264).
Apache License 2.0
78 stars 7 forks source link
fmp4 h264 hls http http-streaming ios iphone linux mjpg mp4 mp4-streaming mp4-video pi-camera python raspberry-pi streaming v4l2 v4l2-m2m video webcam

Fmp4streamer

How does it work | Capabilities | Installation | Running | Viewing | Configuration | Raspberry | Latency | Tested cameras | Roadmap | Motivation | Changelog

Fmp4streamer streams your V4L2 camera directly to any browser and media player as H264 inside fragmented mp4. It is compatible with desktops and mobiles. You can add it your phone's home screen too!


How does it work

Fmp4streamer setups the V4L2 device, reads the H264 or MJPGH264 stream from it (or the YUYV, MJPG stream and converts to H264 with a M2M V4L2 device), adds MP4 header (fragmented mp4 - fmp4) and serves it via HTTP. On the browser side it works with only one html5 video tag, no js needed. It's pretty lightweight.

Capabilities

Installation

   curl -sSL https://github.com/soyersoyer/fmp4streamer/archive/refs/tags/v3.4.7.tar.gz | tar -xvz
   ln -fns fmp4streamer-3.4.7 fmp4streamer

Running

Viewing

When fmp4streamer.py is running the stream can be viewed from any browser via the following url. _ipaddress is the ip address or hostname of your computer, and port (default: 8000) is the port you set in the configuration section.

http://<ip_address>:<port>/

If you want to view the stream via your favourite media player, you can use the

http://<ip_address>:<port>/stream.mp4

url.

Configuration

You can start with the fmp4streamer.conf.dist:

cp fmp4streamer.conf.dist fmp4streamer.conf

Which contains:

[server]
listen =
port = 8000
[/dev/video0]
width = 640
height = 480
fps = 30

# Device capture format (default: H264)
# H264, MJPGH264, YUYV, MJPG, JPEG
# capture_format = H264

# Decoder M2M device (default: disabled)
# To decode the stream to a compatible format with the encoder (eg MJPG -> NV12 -> H264)
# decoder = /dev/video10

# Encoder M2M device (default: disabled)
# To encode the stream to H264 (eg YUYV -> H264 or MJPG -> NV12 -> H264)
# encoder = /dev/video11

# Auto Sleep mode (default: yes)
# Sleep the camera when no one is watching the stream
# auto_sleep = yes

# Sets the MP4 TRAK rotation matrix (default: 0)
# 0, 90, 180, 270
# rotation = 0

# Controls

# you can set any V4L2 control too, list them with the -l option
h264_profile = High
h264_level = 4.2
h264_i_frame_period = 15

uvcx_h264_i_frame_period = 1000
uvcx_h264_profile = High

# Advanced (change only if you know, what you are doing)

# Buffer memory configurations (MMAP or DMABUF)
# Sometimes contigous memory is not large enough for hardwares and tuning needed

# default: DMABUF if encoder or decoder else MMAP
# capture_memory = DMABUF

# decoder_memory = MMAP-DMABUF
# encoder_memory = MMAP-MMAP

# Input format for the decoder (default: MJPG if capture_format == JPEG else capture_format)
# If the capture_format isn't supported by the decoder directly,
# but it can decode it with another format eg (capture_format = JPEG, decoder_input_format = MJPG)
# decoder_input_format = MJPG

# Input format for the encoder (default: NV12 if decoder else capture_format)
# encoder_input_format = NV12

You can set all the V4L2 or UVCX H264 controls via the configuration file. List them with -l option:

$ python3 fmp4streamer.py -l
Device: /dev/video0
Name: Logitech Webcam C930e
Driver: uvcvideo

Controls
brightness = 128    ( default: 128 min: 0 max: 255)
contrast = 128  ( default: 128 min: 0 max: 255)
saturation = 128    ( default: 128 min: 0 max: 255)
white_balance_temperature_auto = 1  ( default: 1 min: 0 max: 1)
gain = 255  ( default: 0 min: 0 max: 255)
power_line_frequency = 50 Hz    ( default: 60 Hz values: 'Disabled' '50 Hz' '60 Hz' )
white_balance_temperature = 4000    ( default: 4000 min: 2000 max: 7500)
sharpness = 128 ( default: 128 min: 0 max: 255)
backlight_compensation = 0  ( default: 0 min: 0 max: 1)
exposure_auto = Aperture Priority Mode  ( default: Aperture Priority Mode values: 'Manual Mode' 'Aperture Priority Mode' )
exposure_absolute = 250 ( default: 250 min: 3 max: 2047)
exposure_auto_priority = 1  ( default: 0 min: 0 max: 1)
pan_absolute = 0    ( default: 0 min: -36000 max: 36000 step: 3600)
tilt_absolute = 0   ( default: 0 min: -36000 max: 36000 step: 3600)
focus_absolute = 0  ( default: 0 min: 0 max: 255 step: 5)
focus_auto = 1  ( default: 1 min: 0 max: 1)
zoom_absolute = 100 ( default: 100 min: 100 max: 400)
uvcx_logitech_led1_mode = Auto  ( default: Off values: 'Off' 'On' 'Blink' 'Auto' )
uvcx_logitech_led1_frequency = 0    ( default: 0 min: 0 max: 255)
uvcx_h264_stream_mux = H264 ( default: None values: 'None' 'H264' )
uvcx_h264_width = 1280  ( default: 1920 min: 160 max: 1920)
uvcx_h264_height = 720  ( default: 1080 min: 120 max: 1080)
uvcx_h264_frame_interval = 333333   ( default: 333333 min: 333333 max: 2000000)
uvcx_h264_bitrate = 3000000 ( default: 3000000 min: 64000 max: 12000000)
uvcx_h264_rate_control_mode = VBR   ( default: CBR values: 'CBR' 'VBR' 'Const QP' )
uvcx_h264_profile = High    ( default: Constrained values: 'Constrained' 'Baseline' 'Main' 'High' )
uvcx_h264_i_frame_period = 1000 ( default: 10000 min: 0 max: 50000)
uvcx_h264_slice_mode = Off  ( default: SlicesPerFrame values: 'Off' 'BitsPerSlice' 'MBsPerSlice' 'SlicesPerFrame' )
uvcx_h264_slice_units = 4   ( default: 4 min: 0 max: 68)
uvcx_h264_entropy = CAVLC   ( default: CAVLC values: 'CAVLC' 'CABAC' )
uvcx_h264_usage = Realtime  ( default: Realtime values: 'Realtime' 'Broadcast' 'Storage' )
uvcx_h264_leaky_bucket_size = 1000  ( default: 1000 min: 500 max: 4000)

To set one, put ctrl_name = Value into fmp4streamer.conf under the device

Raspberry

The Raspberry PI camera works with the default config on Raspberry OS Buster version. If you are using Bullseye with the PI cameras, you should setup the old camera stack

Edit /boot/config.txt, remove the line "camera_auto_detect=1", and add "start_x=1" and "gpu_mem=128". Rebooting at this stage will reload the old V4L2 driver.

If you have a raspberry with an USB camera which supports YUYV format, you can use this configuration:

[server]
listen = 
port = 8000

[/dev/video0]
width = 640
height = 480
fps = 30
capture_format = YUYV
encoder = /dev/video11

[/dev/video11]
# you can set any V4L2 control too, list them with the -l option
h264_profile = High
h264_level = 4.2
h264_i_frame_period = 15

If you have a raspberry with an USB camera which supports MJPG format, you can use this configuration:

[server]
listen = 
port = 8000

[/dev/video0]
width = 640
height = 480
fps = 30
capture_format = MJPG
decoder = /dev/video10
encoder = /dev/video11

[/dev/video11]
# you can set any V4L2 control too, list them with the -l option
h264_profile = High
h264_level = 4.2
h264_i_frame_period = 15

Latency

You can reduce the latency with lower I-Frame periods. You can set with the h264_i_frame_period or uvcx_h264_i_frame_period controls.

Tested Cameras

Roadmap

Motivation

I wanted to stream my raspberry camera to the browser. I found some solution, but I think they are not optimal or too heavy (more than 100MB) or too hard to install, so I decided to write one which doesn't have too many dependencies.

Fmp4streamer doesn't have any dependencies other than Python and V4L2, but they are installed by default.

It adds fMP4 (fragmented MP4) headers to the h264 stream. It uses the python http server to serve it to the browser.

The browsers play it with only one html5 video tag. No javascript needed.

Safari on iOS plays it only with HLS playlists, but it works too. And the playlists added to the index.html of course.

Inspired from

UV4L

131/h264-live-player

dans98/pi-h264-to-browser

samirkumardas/jmuxer

Media Source Extensions

thinkski/berrymse