raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
894 stars 189 forks source link

[BUG] Setting profile="high" for H264Encoder causes OSError: [Errno 22] Invalid argument #1097

Open 03vmate opened 2 months ago

03vmate commented 2 months ago

Trying to set profile="high" for H264Encoder causes the following:

Traceback (most recent call last):
  File "/home/pi/test.py", line 24, in <module>
    picam2.start_encoder(encoder, output, quality=Quality.HIGH)
  File "/usr/lib/python3/dist-packages/picamera2/picamera2.py", line 1712, in start_encoder
    _encoder.start(quality=quality)
  File "/usr/lib/python3/dist-packages/picamera2/encoders/encoder.py", line 231, in start
    self._start()
  File "/usr/lib/python3/dist-packages/picamera2/encoders/h264_encoder.py", line 87, in _start
    super()._start()
  File "/usr/lib/python3/dist-packages/picamera2/encoders/v4l2_encoder.py", line 111, in _start
    fcntl.ioctl(self.vd, VIDIOC_S_EXT_CTRLS, ext)
OSError: [Errno 22] Invalid argument

baseline and main work properly, only high causes the exception.

Example code :

from picamera2 import Picamera2
from picamera2.encoders import H264Encoder, Quality
from picamera2.outputs import FileOutput
import time

picam2 = Picamera2()

config = picam2.create_video_configuration(
    raw = None,
    lores = None,
    main = {
        "size": (1440, 1080)
    }
)

picam2.align_configuration(config)
picam2.configure(config)
picam2.set_controls({"FrameDurationLimits": (50000, 50000)}) # 20 FPS

output_file = open("output.h264", "wb")
output = FileOutput(output_file)
encoder = H264Encoder(repeat=True, iperiod=10, enable_sps_framerate=True, framerate=20, profile="high")
picam2.start_encoder(encoder, output, quality=Quality.HIGH)
picam2.start()

time.sleep(10)

picam2.stop()
picam2.stop_encoder()

Using Pi4 with HQ camera, Python 3.11.2, picamera2 0.3.19, libcamera v0.3.0+65-6ddd79b5, Linux 6.6.31+rpt-rpi-v8

davidplowman commented 2 months ago

Hi, thanks for reporting this. Yes, it does indeed seem to be broken.

The problem is that the value of V4L2_MPEG_VIDEO_H264_PROFILE_HIGH is incorrect in the python-v4l2 package. I'll make up a PR and ask the repository owner to merge the fix. Then we'll have to make up an updated package, so it may all take a few days.

If you want a fix in the meantime, I might check out git clone https://github.com/RaspberryPiFoundation/python-v4l2 and then add the folder where you put it to your PYTHONPATH environment variable. Then, look in the file v4l2.py in there, and find V4L2_MPEG_VIDEO_H264_PROFILE_HIGH. Just above that add the following new line:

V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED,

Also change the range(4) below it to range(5). Then things should work.

03vmate commented 2 months ago

@davidplowman Thanks for the workaround, one semi-related question: I was not able to find anything about the "default" profile when not specifying the profile parameter. What does it default to?

davidplowman commented 2 months ago

Haha, good question. It seems to leave it entirely to the hardware driver which, I think, sets it to... (drum roll)

https://github.com/raspberrypi/linux/blob/rpi-6.6.y/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c#L3302

High! So it looks like leaving it out altogether would also be a workaround. Obviously would be worth checking in practice. Oh well.

The patch has also been merged now, so just waiting for a new apt package to be made up. (You could install it with pip too, but mixing pip and apt packages often seems to lead me to a dark place.)