roflcoopter / viseron

Self-hosted, local only NVR and AI Computer Vision software. With features such as object detection, motion detection, face recognition and more, it gives you the power to keep an eye on your home, office or any other place you want to monitor.
MIT License
1.66k stars 171 forks source link

Using a local usb webcam? #708

Open roflcoopter opened 8 months ago

roflcoopter commented 8 months ago

Discussed in https://github.com/roflcoopter/viseron/discussions/705

Originally posted by **DamonLane** January 21, 2024 Hello, I appreciate the clear documentation but didn't see this possibility mentioned. I'm setting up a single webcam connected to a low powered ARM device, mainly because both are just laying around. I can access the webcam with ffmpeg from inside the Viseron container, but if I skip the host and port inputs and only provide the local path to the camera, Viseron errors: > > Failed setup > Error validating config for domain camera and component ffmpeg: required key not provided @ data['camera_1']['port']. Got None That's not surprising, but is there a way to communicate to Viseron what I'm trying to do? The Gstreamer component gives the same message. I could use ffserver or something similar to provide the steam on localhost where it would have the parameters the camera components expect, but if there's a way to configure the usb source directly it would be more efficient and simpler.
DamonLane commented 8 months ago

Thanks, picking up from that discussion, you suggested:

If you fill in width, height, fps, codec and audio_codec ffprobe should be skipped.

Width and height are parts of the camera config in Viseron and are not the names of inputs in ffmpeg, so would I put them in the camera config? But those are ignored when using raw_command? Oh, I see "most" configuration options are ignored when using raw_command, not all so I put width, height, and fps in the config and not the command.

I only have a superficial understanding of the ffmpeg command format and it seems like if I want to use the parameters Viseron suggests (or maybe just uses as an example?) like rawvideo and also want to minimal processing in ffmpeg, so using copy, those two appear to conflict? In the raw_command example one stream uses rawvideo and the other uses copy. Does using one or the other of those preempt codecs? I tried a few options and couldn't get ffmpeg to work with both codecs and rawvideo, but that command has about a million degrees of freedom so it's hard to test comprehensively. To specify codec and avoid ffprobe, do I have to manually specify parameters instead of using copy?

bsyomov commented 8 months ago

@DamonLane Viseron still need to know video resolution and fps to process your video output of streaming(pipe) raw_command. Your input stream is a v4l, so you need transcode it to something like h264 in segmenter raw_command, and decode to rawvideo, pix_fmt nv12(+optional resize/change fps) for further processing in streaming(pipe) raw_command.

@roflcoopter Name raw_command on both stream and substream level are a bit confusing.

DamonLane commented 8 months ago

Ok, I see those additional Viseron config options and adding those got past the FFprobe timeout. I think I added the parts to the ffmpeg command to specify those inputs, and transcode. Now the camera view gets stuck at the loading circle and the live view eventually says 'camera not found.'

ffmpeg:
  camera:
    camera_one:
      name: bird bath webcam
      host: 111.111.111.111
      port: 1111
      path: /dev/video6
      width: 1280
      height: 720
      fps: 10
      codec: libx264 
      audio_codec: opus
      raw_command: ffmpeg -f video4linux2 -video_size 1280x720 -framerate 10 -i /dev/video6 -c:v libx264 -preset ultrafast -tune zerolatency -f rawvideo -pix_fmt nv12 pipe:1

That exact raw_command spews illegible garbage in stdout in my ssh connection, which I've been assuming would be video if the ssh terminal had a place to put it.

bsyomov commented 8 months ago

Seems like your don't need video codec here. My working example below:

raw_command: ffmpeg_bssdc_cam1 -hide_banner -loglevel error -avoid_negative_ts make_zero -fflags nobuffer -flags low_delay -strict experimental -fflags +genpts -use_wallclock_as_timestamps 1 -vsync 0 -timeout 5000000 -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -rtsp_transport udp -i rtsp://192.168.1.2:554/user=<snip>&password=<snip>&channel=1&stream=0.sdp -vf scale_vaapi=w=848:h=480,denoise_vaapi,hwdownload,format=nv12 -f rawvideo -pix_fmt nv12 pipe:1

It takes input, decode it with vaapi, scale it with vaapi accelerated scaler, download from GPU, and pass it to pipe without encoding...

DamonLane commented 8 months ago

Thanks for your help! If I remove the '-c:v libx264' from the raw_command I get the same result. But that was good to try because it aligns with trying to have info only once, in the Viseron config or in the raw_command, and trying to have a minimal command to get it working before worrying about performance.

If I instead start from your command, replacing the input term and removing '-rtsp_transport udp', I first get ffmpeg_bssdc_cam1: command not found. Oh yes of course that's your alias or something, so switch to ffmpeg, then: Option timeout not found. Ok that one is more surprising, but I remove '-timeout 5000000' and try again, then:

[AVHWDeviceContext @ 0xaaaad2c50880] Failed to initialise VAAPI connection: -1 (unknown libva error).
Device creation failed: -5.
[rawvideo @ 0xaaaad2c51ee0] No device available for decoder: device type vaapi needed for codec rawvideo.
Device setup failed for decoder on input stream #0:0 : Input/output error

even though:

Hardware acceleration methods:
vdpau
cuda
vaapi
drm
opencl
vulkan

Anyway, returning to my minimum command, I can drop the performance tags ChatGPT included when it helped get to a working command. This minimum one: raw_command: ffmpeg -f video4linux2 -i /dev/video6 -f rawvideo -pix_fmt nv12 pipe:1

returns the scrolling illegible characters and when stopped by pressing 'q', may leave readable lines like this:

frame=   22 fps=3.6 q=-0.0 Lsize=   28446kB time=00:00:02.20 bitrate=105922.6kbits/s dup=20 drop=0 speed=0.363x    
video:29700kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

I usually test commands first over ssh on the server's own ffmpeg, then run again inside Viseron's container. Just now, the latter also gave a waterfall of characters, but won't stop with the 'q' button like the command outside the container will, and inside the container it doesn't print the readable lines at the end. After killing it with control-C, the webcam device was busy and ffmpeg was using most of the cpu. Maybe that sheds light on Viseron showing the camera like it's loading? I think that's why you suggesting transcoding/decoding, because ffmpeg maybe isn't giving Viseron what it expects?