rpi: add unified rpiCameraH264Profile, rpiCameraH264Level params (#5894)

These replace rpiCameraHardwareH264Profile, rpiCameraHardwareH264Level, rpiCameraSoftwareH264Profile, rpiCameraSoftwareH264Level.
This commit is contained in:
Alessandro Ros
2026-06-25 22:07:36 +02:00
committed by GitHub
parent b91affa054
commit 07d0e232b2
9 changed files with 249 additions and 126 deletions
+12
View File
@@ -926,12 +926,24 @@ components:
deprecated: true
rpiCameraHardwareH264Profile:
type: string
nullable: true
deprecated: true
rpiCameraHardwareH264Level:
type: string
nullable: true
deprecated: true
rpiCameraSoftwareH264Profile:
type: string
nullable: true
deprecated: true
rpiCameraSoftwareH264Level:
type: string
nullable: true
deprecated: true
rpiCameraH264Profile:
type: string
rpiCameraH264Level:
type: string
rpiCameraJPEGQuality:
type: integer
format: uint64
+39 -41
View File
@@ -93,47 +93,45 @@ func TestConfFromFile(t *testing.T) {
pa, ok := conf.Paths["cam1"]
require.Equal(t, true, ok)
require.Equal(t, &Path{
Name: "cam1",
Source: "publisher",
SourceOnDemandStartTimeout: 10 * Duration(time.Second),
SourceOnDemandCloseAfter: 10 * Duration(time.Second),
OverridePublisher: true,
AlwaysAvailableTracks: []AlwaysAvailableTrack{},
RecordPath: "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f",
RecordFormat: RecordFormatFMP4,
RecordPartDuration: Duration(1 * time.Second),
RecordMaxPartSize: 50 * 1024 * 1024,
RecordSegmentDuration: 3600000000000,
RecordDeleteAfter: 86400000000000,
RTSPUDPSourcePortRange: []uint{10000, 65535},
WHEPSTUNGatherTimeout: 5 * Duration(time.Second),
WHEPHandshakeTimeout: 10 * Duration(time.Second),
WHEPTrackGatherTimeout: 2 * Duration(time.Second),
RPICameraWidth: 1920,
RPICameraHeight: 1080,
RPICameraContrast: 1,
RPICameraSaturation: 1,
RPICameraSharpness: 1,
RPICameraExposure: "normal",
RPICameraAWB: "auto",
RPICameraAWBGains: []float64{0, 0},
RPICameraDenoise: "off",
RPICameraMetering: "centre",
RPICameraFPS: 30,
RPICameraAfMode: "continuous",
RPICameraAfRange: "normal",
RPICameraAfSpeed: "normal",
RPICameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX",
RPICameraCodec: "auto",
RPICameraIDRPeriod: 60,
RPICameraBitrate: 5000000,
RPICameraHardwareH264Profile: "main",
RPICameraHardwareH264Level: "4.1",
RPICameraSoftwareH264Profile: "baseline",
RPICameraSoftwareH264Level: "4.1",
RPICameraMJPEGQuality: 60,
RunOnDemandStartTimeout: 5 * Duration(time.Second),
RunOnDemandCloseAfter: 10 * Duration(time.Second),
Name: "cam1",
Source: "publisher",
SourceOnDemandStartTimeout: 10 * Duration(time.Second),
SourceOnDemandCloseAfter: 10 * Duration(time.Second),
OverridePublisher: true,
AlwaysAvailableTracks: []AlwaysAvailableTrack{},
RecordPath: "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f",
RecordFormat: RecordFormatFMP4,
RecordPartDuration: Duration(1 * time.Second),
RecordMaxPartSize: 50 * 1024 * 1024,
RecordSegmentDuration: 3600000000000,
RecordDeleteAfter: 86400000000000,
RTSPUDPSourcePortRange: []uint{10000, 65535},
WHEPSTUNGatherTimeout: 5 * Duration(time.Second),
WHEPHandshakeTimeout: 10 * Duration(time.Second),
WHEPTrackGatherTimeout: 2 * Duration(time.Second),
RPICameraWidth: 1920,
RPICameraHeight: 1080,
RPICameraContrast: 1,
RPICameraSaturation: 1,
RPICameraSharpness: 1,
RPICameraExposure: "normal",
RPICameraAWB: "auto",
RPICameraAWBGains: []float64{0, 0},
RPICameraDenoise: "off",
RPICameraMetering: "centre",
RPICameraFPS: 30,
RPICameraAfMode: "continuous",
RPICameraAfRange: "normal",
RPICameraAfSpeed: "normal",
RPICameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX",
RPICameraCodec: "auto",
RPICameraIDRPeriod: 60,
RPICameraBitrate: 5000000,
RPICameraH264Profile: "auto",
RPICameraH264Level: "4.1",
RPICameraMJPEGQuality: 60,
RunOnDemandStartTimeout: 5 * Duration(time.Second),
RunOnDemandCloseAfter: 10 * Duration(time.Second),
}, pa)
}()
+59 -27
View File
@@ -314,10 +314,12 @@ type Path struct {
RPICameraBitrate uint `json:"rpiCameraBitrate"`
RPICameraProfile *string `json:"rpiCameraProfile,omitempty" deprecated:"true"`
RPICameraLevel *string `json:"rpiCameraLevel,omitempty" deprecated:"true"`
RPICameraHardwareH264Profile string `json:"rpiCameraHardwareH264Profile"`
RPICameraHardwareH264Level string `json:"rpiCameraHardwareH264Level"`
RPICameraSoftwareH264Profile string `json:"rpiCameraSoftwareH264Profile"`
RPICameraSoftwareH264Level string `json:"rpiCameraSoftwareH264Level"`
RPICameraHardwareH264Profile *string `json:"rpiCameraHardwareH264Profile,omitempty" deprecated:"true"`
RPICameraHardwareH264Level *string `json:"rpiCameraHardwareH264Level,omitempty" deprecated:"true"`
RPICameraSoftwareH264Profile *string `json:"rpiCameraSoftwareH264Profile,omitempty" deprecated:"true"`
RPICameraSoftwareH264Level *string `json:"rpiCameraSoftwareH264Level,omitempty" deprecated:"true"`
RPICameraH264Profile string `json:"rpiCameraH264Profile"`
RPICameraH264Level string `json:"rpiCameraH264Level"`
RPICameraJPEGQuality *uint `json:"rpiCameraJPEGQuality,omitempty" deprecated:"true"`
RPICameraMJPEGQuality uint `json:"rpiCameraMJPEGQuality"`
RPICameraPrimaryName string `json:"-"` // filled by Validate()
@@ -388,10 +390,8 @@ func (pconf *Path) setDefaults() {
pconf.RPICameraCodec = "auto"
pconf.RPICameraIDRPeriod = 60
pconf.RPICameraBitrate = 5000000
pconf.RPICameraHardwareH264Profile = "main"
pconf.RPICameraHardwareH264Level = "4.1"
pconf.RPICameraSoftwareH264Profile = "baseline"
pconf.RPICameraSoftwareH264Level = "4.1"
pconf.RPICameraH264Profile = "auto"
pconf.RPICameraH264Level = "4.1"
pconf.RPICameraMJPEGQuality = 60
// Hooks
@@ -628,37 +628,69 @@ func (pconf *Path) validate(
if pconf.RPICameraProfile != nil {
l.Log(logger.Warn, "parameter 'rpiCameraProfile' is deprecated"+
" and has been replaced with 'rpiCameraHardwareH264Profile'")
pconf.RPICameraHardwareH264Profile = *pconf.RPICameraProfile
pconf.RPICameraHardwareH264Profile = pconf.RPICameraProfile
}
if pconf.RPICameraLevel != nil {
l.Log(logger.Warn, "parameter 'rpiCameraLevel' is deprecated"+
" and has been replaced with 'rpiCameraHardwareH264Level'")
pconf.RPICameraHardwareH264Level = *pconf.RPICameraLevel
pconf.RPICameraHardwareH264Level = pconf.RPICameraLevel
}
switch pconf.RPICameraHardwareH264Profile {
case "baseline", "main", "high":
if pconf.RPICameraHardwareH264Profile != nil {
l.Log(logger.Warn, "parameter 'rpiCameraHardwareH264Profile' is deprecated"+
" and has been replaced with 'rpiCameraH264Profile'")
switch *pconf.RPICameraHardwareH264Profile {
case "baseline", "main", "high":
default:
return fmt.Errorf("invalid 'rpiCameraHardwareH264Profile' value")
}
}
if pconf.RPICameraHardwareH264Level != nil {
l.Log(logger.Warn, "parameter 'rpiCameraHardwareH264Level' is deprecated"+
" and has been replaced with 'rpiCameraH264Level'")
switch *pconf.RPICameraHardwareH264Level {
case "4.0", "4.1", "4.2":
default:
return fmt.Errorf("invalid 'rpiCameraHardwareH264Level' value")
}
}
if pconf.RPICameraSoftwareH264Profile != nil {
l.Log(logger.Warn, "parameter 'rpiCameraSoftwareH264Profile' is deprecated"+
" and has been replaced with 'rpiCameraH264Profile'")
switch *pconf.RPICameraSoftwareH264Profile {
case "baseline", "main", "high":
default:
return fmt.Errorf("invalid 'rpiCameraSoftwareH264Profile' value")
}
}
if pconf.RPICameraSoftwareH264Level != nil {
l.Log(logger.Warn, "parameter 'rpiCameraSoftwareH264Level' is deprecated"+
" and has been replaced with 'rpiCameraH264Level'")
switch *pconf.RPICameraSoftwareH264Level {
case "4.0", "4.1", "4.2":
default:
return fmt.Errorf("invalid 'rpiCameraSoftwareH264Level' value")
}
}
switch pconf.RPICameraH264Profile {
case "auto", "baseline", "main", "high":
default:
return fmt.Errorf("invalid 'rpiCameraHardwareH264Profile' value")
return fmt.Errorf("invalid 'rpiCameraH264Profile' value")
}
switch pconf.RPICameraHardwareH264Level {
switch pconf.RPICameraH264Level {
case "4.0", "4.1", "4.2":
default:
return fmt.Errorf("invalid 'rpiCameraHardwareH264Level' value")
}
switch pconf.RPICameraSoftwareH264Profile {
case "baseline", "main", "high":
default:
return fmt.Errorf("invalid 'rpiCameraSoftwareH264Profile' value")
}
switch pconf.RPICameraSoftwareH264Level {
case "4.0", "4.1", "4.2":
default:
return fmt.Errorf("invalid 'rpiCameraSoftwareH264Level' value")
return fmt.Errorf("invalid 'rpiCameraH264Level' value")
}
if pconf.RPICameraJPEGQuality != nil {
@@ -13,45 +13,43 @@ import (
)
type cameraParams struct {
LogLevel string
CameraID uint32
Width uint32
Height uint32
HFlip bool
VFlip bool
Brightness float32
Contrast float32
Saturation float32
Sharpness float32
Exposure string
AWB string
AWBGainRed float32
AWBGainBlue float32
Denoise string
Shutter uint32
Metering string
Gain float32
EV float32
ROI string
HDR bool
TuningFile string
Mode string
FPS float32
AfMode string
AfRange string
AfSpeed string
LensPosition float32
AfWindow string
FlickerPeriod uint32
TextOverlayEnable bool
TextOverlay string
Codec string
IDRPeriod uint32
Bitrate uint32
HardwareH264Profile string
HardwareH264Level string
SoftwareH264Profile string
SoftwareH264Level string
LogLevel string
CameraID uint32
Width uint32
Height uint32
HFlip bool
VFlip bool
Brightness float32
Contrast float32
Saturation float32
Sharpness float32
Exposure string
AWB string
AWBGainRed float32
AWBGainBlue float32
Denoise string
Shutter uint32
Metering string
Gain float32
EV float32
ROI string
HDR bool
TuningFile string
Mode string
FPS float32
AfMode string
AfRange string
AfSpeed string
LensPosition float32
AfWindow string
FlickerPeriod uint32
TextOverlayEnable bool
TextOverlay string
Codec string
IDRPeriod uint32
Bitrate uint32
H264Profile string
H264Level string
SecondaryWidth uint32
SecondaryHeight uint32
@@ -102,13 +100,51 @@ func (p *cameraParams) fromConf(logLevel conf.LogLevel, cnf *conf.Path) {
p.FlickerPeriod = uint32(cnf.RPICameraFlickerPeriod)
p.TextOverlayEnable = cnf.RPICameraTextOverlayEnable
p.TextOverlay = cnf.RPICameraTextOverlay
p.Codec = cnf.RPICameraCodec
p.Codec = func() string {
if cnf.RPICameraCodec == "auto" {
if !cnf.RPICameraSecondary {
if supportsHardwareH264() {
return "hardwareH264"
}
return "softwareH264"
}
return "mjpeg"
}
return cnf.RPICameraCodec
}()
p.IDRPeriod = uint32(cnf.RPICameraIDRPeriod)
p.Bitrate = uint32(cnf.RPICameraBitrate)
p.HardwareH264Profile = cnf.RPICameraHardwareH264Profile
p.HardwareH264Level = cnf.RPICameraHardwareH264Level
p.SoftwareH264Profile = cnf.RPICameraSoftwareH264Profile
p.SoftwareH264Level = cnf.RPICameraSoftwareH264Level
p.H264Profile = func() string {
if p.Codec == "hardwareH264" && cnf.RPICameraHardwareH264Profile != nil {
return *cnf.RPICameraHardwareH264Profile
}
if p.Codec == "softwareH264" && cnf.RPICameraSoftwareH264Profile != nil {
return *cnf.RPICameraSoftwareH264Profile
}
if cnf.RPICameraH264Profile == "auto" {
if p.Codec == "hardwareH264" {
return "main"
}
return "baseline"
}
return cnf.RPICameraH264Profile
}()
p.H264Level = func() string {
if p.Codec == "hardwareH264" && cnf.RPICameraHardwareH264Level != nil {
return *cnf.RPICameraHardwareH264Level
}
if p.Codec == "softwareH264" && cnf.RPICameraSoftwareH264Level != nil {
return *cnf.RPICameraSoftwareH264Level
}
return cnf.RPICameraH264Level
}()
p.SecondaryWidth = uint32(cnf.RPICameraSecondaryWidth)
p.SecondaryHeight = uint32(cnf.RPICameraSecondaryHeight)
@@ -1 +1 @@
4d9f7785e225af4c84d54dc36a5e44fc255188e3a2db291ccf7fa3093adc549d
63f305e54d124427d39f3f428cbc22ca004bc5f0f5ea550ed2998299f11c4b4a
@@ -1 +1 @@
8448f91064c9d659aa28dd22141ab4b82918d5990a8c3939cebcb2013a58f346
5873f9fc54cb80714bf7ca577481de3a6ff9b928325b4ec87dde99c3bfd5b3f3
@@ -1 +1 @@
v2.6.0
v2.6.1
@@ -0,0 +1,44 @@
//go:build (linux && arm) || (linux && arm64)
package rpicamera
import (
"bytes"
"os"
"syscall"
"unsafe"
)
type v4l2Capability struct {
Driver [16]byte
Card [32]byte
BusInfo [32]byte
Version uint32
Capabilities uint32
DeviceCaps uint32
Reserved [3]uint32
}
const VIDIOC_QUERYCAP = 0x80685600
func supportsHardwareH264() bool {
file, err := os.OpenFile("/dev/video11", os.O_RDWR, 0)
if err != nil {
return false
}
defer file.Close()
var caps v4l2Capability
_, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
file.Fd(),
uintptr(VIDIOC_QUERYCAP),
uintptr(unsafe.Pointer(&caps)),
)
if errno != 0 {
return false
}
return bytes.HasPrefix(caps.Card[:], []byte("bcm2835-codec"))
}
+12 -11
View File
@@ -701,22 +701,23 @@ pathDefaults:
# format is the one of the strftime() function.
rpiCameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX"
# Codec (auto, hardwareH264, softwareH264 or mjpeg).
# When is "auto" and stream is primary, it defaults to hardwareH264 (if available) or softwareH264.
# When is "auto" and stream is secondary, it defaults to mjpeg.
# When is "auto", it defaults to:
# * hardwareH264 when stream is primary and hardware encoder is available
# * softwareH264 when stream is primary and hardware encoder is not available
# * mjpeg when stream is secondary
rpiCameraCodec: auto
# Period between IDR frames (when codec is hardwareH264 or softwareH264).
rpiCameraIDRPeriod: 60
# Bitrate (when codec is hardwareH264 or softwareH264).
rpiCameraBitrate: 5000000
# Hardware H264 profile (baseline, main or high) (when codec is hardwareH264).
rpiCameraHardwareH264Profile: main
# Hardware H264 level (4.0, 4.1 or 4.2) (when codec is hardwareH264).
rpiCameraHardwareH264Level: "4.1"
# Software H264 profile (baseline, main or high) (when codec is softwareH264).
rpiCameraSoftwareH264Profile: baseline
# Software H264 level (4.0, 4.1 or 4.2) (when codec is softwareH264).
rpiCameraSoftwareH264Level: "4.1"
# M-JPEG JPEG quality (when codec is mjpeg).
# H264 profile (auto, baseline, main or high).
# When is "auto", it defaults to:
# * main when codec is hardwareH264
# * baseline when codec is softwareH264
rpiCameraH264Profile: auto
# H264 level (4.0, 4.1 or 4.2).
rpiCameraH264Level: "4.1"
# M-JPEG quality (0-100).
rpiCameraMJPEGQuality: 60
###############################################