3

I have a 1080p webcam connected to a Raspberry Pi 4B over USB. The camera supports the following formats:

Raw       :     yuyv422 :           YUYV 4:2:2
Compressed:       mjpeg :          Motion-JPEG

I would like to use ffmpeg to stream the footage to file, using hardware-accelerated encoding, so I'm attempting to use the h264_v4l2m2m codec.

Problem is, if I want 1080p to work at a decent frame rate, I need to use the mjpeg stream from the camera. But this makes the output codec complain.

Here's my command:

$ ffmpeg -y -f v4l2 -framerate 24 -video_size 1920x1080 -input_format mjpeg -i /dev/video0 -c:v h264_v4l2m2m -r 24 -b:v 2386092 lmao.mp4

And the relevant output:

...
[h264_v4l2m2m @ 0xf4c2d0] Using device /dev/video11
[h264_v4l2m2m @ 0xf4c2d0] driver 'bcm2835-codec' on card 'bcm2835-codec-encode' in mplane mode
[h264_v4l2m2m @ 0xf4c2d0] requesting formats: output=YU12 capture=H264
[h264_v4l2m2m @ 0xf4c2d0] Encoder requires yuv420p pixel format.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!

What's the deal?! This seems very limiting.

Does anyone know of alternative solutions? I've tried using the h264_omx codec, but at least on stock Raspberry Pi OS, it just complains about missing libraries, so I imagine I'd have to compile ffmpeg myself.

I'm on Raspberry Pi OS Bullseye, using ffmpeg version 4.3.4-0+deb11u1+rpt1.

Archimaredes
  • 139
  • 1
  • 3

3 Answers3

0

I'm trying to achieve the same result without success, for now, but in your case the missing parameter to avoid ffmpeg error is -pix_fmt yuv420p, so your command should be:

$ ffmpeg -y -f v4l2 -framerate 24 -video_size 1920x1080 -input_format mjpeg -i /dev/video0 -c:v h264_v4l2m2m -pix_fmt yuv420p -r 24 -b:v 2386092 lmao.mp4
Davide
  • 1
  • 1
0

You need convert to yuv420p by add filter

ffmpeg -f v4l2 -framerate 30 -video_size hd1080 -input_format mjpeg -i /dev/video0 -vf "format=yuv420p" -c:v h264_v4l2m2m -b:v 6000k -t 20  output.mp4
coolle
  • 1
0

And I suggest use libopenh264 with high profile.

ffmpeg -framerate 25 -i inVideo.yuvj422p -profile:v high -c:v libopenh264 -b:v 4000000 -allow_skip_frames 1 -maxrate 7000000 outVideo.mkv

Also you can measure how long encoding works using

time ffmpeg -framerate 25 -i inVideo.yuvj422p -profile:v high -c:v libopenh264 -b:v 4000000 -allow_skip_frames 1 -maxrate 7000000 outVideo.mkv

If your ffmpeg version doesn't build with libopenh264 then you should build with libopenh264, for example

cd $HOME
git clone https://git.ffmpeg.org/ffmpeg.git
mkdir ffmpeg_build ffmpeg_build_artifacts
cd ffmpeg
PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" ./configure \
  --prefix="$HOME/ffmpeg_build/" \
  --pkg-config-flags="--static" \
  --extra-cflags="-I$HOME/ffmpeg_build/include" \
  --extra-ldflags="-L$HOME/ffmpeg_build/lib" \
  --extra-libs="-lpthread -lm" \
  --ld="g++" \
  --bindir="$HOME/ffmpeg_build_artifacts" \
  --enable-gpl \
  --enable-libopenh264
make -j16
make install

In this case use full path to ffmpeg, for example

$HOME/ffmpeg_build_artifacts/ffmpeg -framerate 25 -i inVideo.yuvj422p -profile:v high -c:v libopenh264 -b:v 4000000 -allow_skip_frames 1 -maxrate 7000000 outVideo.mkv