geerlingguy / pi-dev-playbook

Raspberry Pi setup and configuration via Ansible.
https://www.jeffgeerling.com/blog/2020/i-replaced-my-macbook-pro-raspberry-pi-4-8gb-day
MIT License
59 stars 11 forks source link

Document video chat/streaming/recording options with the Pi 4 #4

Open geerlingguy opened 4 years ago

geerlingguy commented 4 years ago

I have a couple Logitech C920 webcams, and I wanted to see if I could use them while streaming and/or recording clips at 1080p... the problem is "it's complicated", and unlike macOS where there are literally a dozen or so free options with fancy/simple GUIs for the purpose, on Linux/RPi, it's a lot more complex.

The most reliable way to capture video is with ffmpeg, but its usage is inscrutable for beginners. And maybe not impossible for me, but it still requires a lot of futzing around.

After reading this article about streaming 1080p content to YouTube directly (without killing your Pi's poor CPU), it was apparent I was in luck that my Logitech C920 has a built-in H.246 encoder that puts out a pre-compressed stream.

Using this incantation gets the video and dumps it into an mp4 file, with minimal CPU usage:

ffmpeg -f v4l2 -codec:v h264 -framerate 30 -video_size 1920x1080 -itsoffset 0.5 -i /dev/video0 -copyinkf -codec:v copy -codec:a aac -ab 128k -g 10 -f mp4 test.mp4

Using a simpler/more standard example from ffmpeg's documentation, however, results in the Pi's CPU struggling to maintain 5 fps:

ffmpeg -f v4l2 -framerate 30 -video_size 1920x1080 -i /dev/video0 output.mkv

You might wonder, 'how do you know the webcam is at /dev/video0? Well, find it with:

$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
    /dev/video10
    /dev/video11
    /dev/video12

bcm2835-isp (platform:bcm2835-isp):
    /dev/video13
    /dev/video14
    /dev/video15
    /dev/video16

HD Pro Webcam C920 (usb-0000:01:00.0-1.2.3):
    /dev/video0
    /dev/video1

Now, onto finding a way to get my audio interface into the stream...

geerlingguy commented 4 years ago

For audio, I can get my audio device using:

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: b1 [bcm2835 HDMI 1], device 0: bcm2835 HDMI 1 [bcm2835 HDMI 1]
  Subdevices: 4/4
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
card 1: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
  Subdevices: 4/4
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
card 2: U192k [UMC202HD 192k], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

$ arecord --list-devices
**** List of CAPTURE Hardware Devices ****
card 2: U192k [UMC202HD 192k], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 3: C920 [HD Pro Webcam C920], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

That seems to correspond to -i hw:2,0, but I could be wrong...

geerlingguy commented 4 years ago

This thread helped me figure out the audio issue; it has to do with alsa not being able to load the device correctly, it seems. I had to create an .asoundrc file with my preferences:

$ cat ~/.asoundrc
pcm.!default {
        type hw
        card 2
}

ctl.!default {
        type hw
        card 2
}

See docs: https://www.alsa-project.org/main/index.php/Asoundrc

But I was still getting the following error:

[alsa @ 0x55b31e38c0] cannot set sample format 0x10000 2 (Invalid argument)
hw:2,0: Input/output error
geerlingguy commented 4 years ago

So I can get a successful A/V stream all from the camera using:

ffmpeg -ar 44100 -ac 2 -f alsa -i hw:3,0 -f v4l2 -codec:v h264 -framerate 30 -video_size 1920x1080 -itsoffset 0.5 -i /dev/video0 -copyinkf -codec:v copy -codec:a aac -ab 128k -g 10 -f mp4 test.mp4

That grabs both audio and video from the attached Logitech C920... and works well, actually. Though I was getting random clicks in the audio every now and then. Note that I was NOT touching anything, and my desk was perfectly still. So maybe something in the chain that ffmpeg sets up for the recording stream :-/

geerlingguy commented 4 years ago

After searching, searching, and searching some more, I finally found this email which had the correct suggestion:

ffmpeg -ar 44100 -ac 2 -f alsa -acodec pcm_s32le -i hw:2,0 -f v4l2 -codec:v h264 -framerate 30 -video_size 1920x1080 -itsoffset 0.5 -i /dev/video0 -copyinkf -codec:v copy -codec:a aac -ab 128k -g 10 -f mp4 test-webcam-audio.mp4

I mean... I worked in radio engineering, and have done live audio at a zillion events, and know my way around most any GUI-based tools. It's no wonder people give up on Linux audio :-(

geerlingguy commented 4 years ago

So... VLC lets you 'open a capture device', but the interface for that, surprising as it may seem, is even more inscrutable than the CLI options for FFmpeg! I couldn't quickly figure out a way to record a 1080p stream using the external USB audio interface, and I've already spent way more time on this part of the experiment than I originally though I'd do.

So... putting a pin in this.

geerlingguy commented 4 years ago

Screenshots of the behavior of BlueJeans and Zoom not seeing any audio source even when two were identified and usable via FFmpeg...

bluejeans-no-audio-option

bluejeans-no-audio-option-2

zoom-no-audio-option

stale[bot] commented 4 years ago

This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution!

Please read this blog post to see the reasons why I mark issues as stale.

stale[bot] commented 4 years ago

This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details.

stale[bot] commented 4 years ago

This issue is no longer marked for closure.