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 deprecated: true
rpiCameraHardwareH264Profile: rpiCameraHardwareH264Profile:
type: string type: string
nullable: true
deprecated: true
rpiCameraHardwareH264Level: rpiCameraHardwareH264Level:
type: string type: string
nullable: true
deprecated: true
rpiCameraSoftwareH264Profile: rpiCameraSoftwareH264Profile:
type: string type: string
nullable: true
deprecated: true
rpiCameraSoftwareH264Level: rpiCameraSoftwareH264Level:
type: string type: string
nullable: true
deprecated: true
rpiCameraH264Profile:
type: string
rpiCameraH264Level:
type: string
rpiCameraJPEGQuality: rpiCameraJPEGQuality:
type: integer type: integer
format: uint64 format: uint64
+39 -41
View File
@@ -93,47 +93,45 @@ func TestConfFromFile(t *testing.T) {
pa, ok := conf.Paths["cam1"] pa, ok := conf.Paths["cam1"]
require.Equal(t, true, ok) require.Equal(t, true, ok)
require.Equal(t, &Path{ require.Equal(t, &Path{
Name: "cam1", Name: "cam1",
Source: "publisher", Source: "publisher",
SourceOnDemandStartTimeout: 10 * Duration(time.Second), SourceOnDemandStartTimeout: 10 * Duration(time.Second),
SourceOnDemandCloseAfter: 10 * Duration(time.Second), SourceOnDemandCloseAfter: 10 * Duration(time.Second),
OverridePublisher: true, OverridePublisher: true,
AlwaysAvailableTracks: []AlwaysAvailableTrack{}, AlwaysAvailableTracks: []AlwaysAvailableTrack{},
RecordPath: "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f", RecordPath: "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f",
RecordFormat: RecordFormatFMP4, RecordFormat: RecordFormatFMP4,
RecordPartDuration: Duration(1 * time.Second), RecordPartDuration: Duration(1 * time.Second),
RecordMaxPartSize: 50 * 1024 * 1024, RecordMaxPartSize: 50 * 1024 * 1024,
RecordSegmentDuration: 3600000000000, RecordSegmentDuration: 3600000000000,
RecordDeleteAfter: 86400000000000, RecordDeleteAfter: 86400000000000,
RTSPUDPSourcePortRange: []uint{10000, 65535}, RTSPUDPSourcePortRange: []uint{10000, 65535},
WHEPSTUNGatherTimeout: 5 * Duration(time.Second), WHEPSTUNGatherTimeout: 5 * Duration(time.Second),
WHEPHandshakeTimeout: 10 * Duration(time.Second), WHEPHandshakeTimeout: 10 * Duration(time.Second),
WHEPTrackGatherTimeout: 2 * Duration(time.Second), WHEPTrackGatherTimeout: 2 * Duration(time.Second),
RPICameraWidth: 1920, RPICameraWidth: 1920,
RPICameraHeight: 1080, RPICameraHeight: 1080,
RPICameraContrast: 1, RPICameraContrast: 1,
RPICameraSaturation: 1, RPICameraSaturation: 1,
RPICameraSharpness: 1, RPICameraSharpness: 1,
RPICameraExposure: "normal", RPICameraExposure: "normal",
RPICameraAWB: "auto", RPICameraAWB: "auto",
RPICameraAWBGains: []float64{0, 0}, RPICameraAWBGains: []float64{0, 0},
RPICameraDenoise: "off", RPICameraDenoise: "off",
RPICameraMetering: "centre", RPICameraMetering: "centre",
RPICameraFPS: 30, RPICameraFPS: 30,
RPICameraAfMode: "continuous", RPICameraAfMode: "continuous",
RPICameraAfRange: "normal", RPICameraAfRange: "normal",
RPICameraAfSpeed: "normal", RPICameraAfSpeed: "normal",
RPICameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX", RPICameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX",
RPICameraCodec: "auto", RPICameraCodec: "auto",
RPICameraIDRPeriod: 60, RPICameraIDRPeriod: 60,
RPICameraBitrate: 5000000, RPICameraBitrate: 5000000,
RPICameraHardwareH264Profile: "main", RPICameraH264Profile: "auto",
RPICameraHardwareH264Level: "4.1", RPICameraH264Level: "4.1",
RPICameraSoftwareH264Profile: "baseline", RPICameraMJPEGQuality: 60,
RPICameraSoftwareH264Level: "4.1", RunOnDemandStartTimeout: 5 * Duration(time.Second),
RPICameraMJPEGQuality: 60, RunOnDemandCloseAfter: 10 * Duration(time.Second),
RunOnDemandStartTimeout: 5 * Duration(time.Second),
RunOnDemandCloseAfter: 10 * Duration(time.Second),
}, pa) }, pa)
}() }()
+59 -27
View File
@@ -314,10 +314,12 @@ type Path struct {
RPICameraBitrate uint `json:"rpiCameraBitrate"` RPICameraBitrate uint `json:"rpiCameraBitrate"`
RPICameraProfile *string `json:"rpiCameraProfile,omitempty" deprecated:"true"` RPICameraProfile *string `json:"rpiCameraProfile,omitempty" deprecated:"true"`
RPICameraLevel *string `json:"rpiCameraLevel,omitempty" deprecated:"true"` RPICameraLevel *string `json:"rpiCameraLevel,omitempty" deprecated:"true"`
RPICameraHardwareH264Profile string `json:"rpiCameraHardwareH264Profile"` RPICameraHardwareH264Profile *string `json:"rpiCameraHardwareH264Profile,omitempty" deprecated:"true"`
RPICameraHardwareH264Level string `json:"rpiCameraHardwareH264Level"` RPICameraHardwareH264Level *string `json:"rpiCameraHardwareH264Level,omitempty" deprecated:"true"`
RPICameraSoftwareH264Profile string `json:"rpiCameraSoftwareH264Profile"` RPICameraSoftwareH264Profile *string `json:"rpiCameraSoftwareH264Profile,omitempty" deprecated:"true"`
RPICameraSoftwareH264Level string `json:"rpiCameraSoftwareH264Level"` RPICameraSoftwareH264Level *string `json:"rpiCameraSoftwareH264Level,omitempty" deprecated:"true"`
RPICameraH264Profile string `json:"rpiCameraH264Profile"`
RPICameraH264Level string `json:"rpiCameraH264Level"`
RPICameraJPEGQuality *uint `json:"rpiCameraJPEGQuality,omitempty" deprecated:"true"` RPICameraJPEGQuality *uint `json:"rpiCameraJPEGQuality,omitempty" deprecated:"true"`
RPICameraMJPEGQuality uint `json:"rpiCameraMJPEGQuality"` RPICameraMJPEGQuality uint `json:"rpiCameraMJPEGQuality"`
RPICameraPrimaryName string `json:"-"` // filled by Validate() RPICameraPrimaryName string `json:"-"` // filled by Validate()
@@ -388,10 +390,8 @@ func (pconf *Path) setDefaults() {
pconf.RPICameraCodec = "auto" pconf.RPICameraCodec = "auto"
pconf.RPICameraIDRPeriod = 60 pconf.RPICameraIDRPeriod = 60
pconf.RPICameraBitrate = 5000000 pconf.RPICameraBitrate = 5000000
pconf.RPICameraHardwareH264Profile = "main" pconf.RPICameraH264Profile = "auto"
pconf.RPICameraHardwareH264Level = "4.1" pconf.RPICameraH264Level = "4.1"
pconf.RPICameraSoftwareH264Profile = "baseline"
pconf.RPICameraSoftwareH264Level = "4.1"
pconf.RPICameraMJPEGQuality = 60 pconf.RPICameraMJPEGQuality = 60
// Hooks // Hooks
@@ -628,37 +628,69 @@ func (pconf *Path) validate(
if pconf.RPICameraProfile != nil { if pconf.RPICameraProfile != nil {
l.Log(logger.Warn, "parameter 'rpiCameraProfile' is deprecated"+ l.Log(logger.Warn, "parameter 'rpiCameraProfile' is deprecated"+
" and has been replaced with 'rpiCameraHardwareH264Profile'") " and has been replaced with 'rpiCameraHardwareH264Profile'")
pconf.RPICameraHardwareH264Profile = *pconf.RPICameraProfile pconf.RPICameraHardwareH264Profile = pconf.RPICameraProfile
} }
if pconf.RPICameraLevel != nil { if pconf.RPICameraLevel != nil {
l.Log(logger.Warn, "parameter 'rpiCameraLevel' is deprecated"+ l.Log(logger.Warn, "parameter 'rpiCameraLevel' is deprecated"+
" and has been replaced with 'rpiCameraHardwareH264Level'") " and has been replaced with 'rpiCameraHardwareH264Level'")
pconf.RPICameraHardwareH264Level = *pconf.RPICameraLevel pconf.RPICameraHardwareH264Level = pconf.RPICameraLevel
} }
switch pconf.RPICameraHardwareH264Profile { if pconf.RPICameraHardwareH264Profile != nil {
case "baseline", "main", "high": 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: 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": case "4.0", "4.1", "4.2":
default: default:
return fmt.Errorf("invalid 'rpiCameraHardwareH264Level' value") return fmt.Errorf("invalid 'rpiCameraH264Level' 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")
} }
if pconf.RPICameraJPEGQuality != nil { if pconf.RPICameraJPEGQuality != nil {
@@ -13,45 +13,43 @@ import (
) )
type cameraParams struct { type cameraParams struct {
LogLevel string LogLevel string
CameraID uint32 CameraID uint32
Width uint32 Width uint32
Height uint32 Height uint32
HFlip bool HFlip bool
VFlip bool VFlip bool
Brightness float32 Brightness float32
Contrast float32 Contrast float32
Saturation float32 Saturation float32
Sharpness float32 Sharpness float32
Exposure string Exposure string
AWB string AWB string
AWBGainRed float32 AWBGainRed float32
AWBGainBlue float32 AWBGainBlue float32
Denoise string Denoise string
Shutter uint32 Shutter uint32
Metering string Metering string
Gain float32 Gain float32
EV float32 EV float32
ROI string ROI string
HDR bool HDR bool
TuningFile string TuningFile string
Mode string Mode string
FPS float32 FPS float32
AfMode string AfMode string
AfRange string AfRange string
AfSpeed string AfSpeed string
LensPosition float32 LensPosition float32
AfWindow string AfWindow string
FlickerPeriod uint32 FlickerPeriod uint32
TextOverlayEnable bool TextOverlayEnable bool
TextOverlay string TextOverlay string
Codec string Codec string
IDRPeriod uint32 IDRPeriod uint32
Bitrate uint32 Bitrate uint32
HardwareH264Profile string H264Profile string
HardwareH264Level string H264Level string
SoftwareH264Profile string
SoftwareH264Level string
SecondaryWidth uint32 SecondaryWidth uint32
SecondaryHeight uint32 SecondaryHeight uint32
@@ -102,13 +100,51 @@ func (p *cameraParams) fromConf(logLevel conf.LogLevel, cnf *conf.Path) {
p.FlickerPeriod = uint32(cnf.RPICameraFlickerPeriod) p.FlickerPeriod = uint32(cnf.RPICameraFlickerPeriod)
p.TextOverlayEnable = cnf.RPICameraTextOverlayEnable p.TextOverlayEnable = cnf.RPICameraTextOverlayEnable
p.TextOverlay = cnf.RPICameraTextOverlay 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.IDRPeriod = uint32(cnf.RPICameraIDRPeriod)
p.Bitrate = uint32(cnf.RPICameraBitrate) p.Bitrate = uint32(cnf.RPICameraBitrate)
p.HardwareH264Profile = cnf.RPICameraHardwareH264Profile
p.HardwareH264Level = cnf.RPICameraHardwareH264Level p.H264Profile = func() string {
p.SoftwareH264Profile = cnf.RPICameraSoftwareH264Profile if p.Codec == "hardwareH264" && cnf.RPICameraHardwareH264Profile != nil {
p.SoftwareH264Level = cnf.RPICameraSoftwareH264Level 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.SecondaryWidth = uint32(cnf.RPICameraSecondaryWidth)
p.SecondaryHeight = uint32(cnf.RPICameraSecondaryHeight) 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. # format is the one of the strftime() function.
rpiCameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX" rpiCameraTextOverlay: "%Y-%m-%d %H:%M:%S - MediaMTX"
# Codec (auto, hardwareH264, softwareH264 or mjpeg). # Codec (auto, hardwareH264, softwareH264 or mjpeg).
# When is "auto" and stream is primary, it defaults to hardwareH264 (if available) or softwareH264. # When is "auto", it defaults to:
# When is "auto" and stream is secondary, it defaults to mjpeg. # * 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 rpiCameraCodec: auto
# Period between IDR frames (when codec is hardwareH264 or softwareH264). # Period between IDR frames (when codec is hardwareH264 or softwareH264).
rpiCameraIDRPeriod: 60 rpiCameraIDRPeriod: 60
# Bitrate (when codec is hardwareH264 or softwareH264). # Bitrate (when codec is hardwareH264 or softwareH264).
rpiCameraBitrate: 5000000 rpiCameraBitrate: 5000000
# Hardware H264 profile (baseline, main or high) (when codec is hardwareH264). # H264 profile (auto, baseline, main or high).
rpiCameraHardwareH264Profile: main # When is "auto", it defaults to:
# Hardware H264 level (4.0, 4.1 or 4.2) (when codec is hardwareH264). # * main when codec is hardwareH264
rpiCameraHardwareH264Level: "4.1" # * baseline when codec is softwareH264
# Software H264 profile (baseline, main or high) (when codec is softwareH264). rpiCameraH264Profile: auto
rpiCameraSoftwareH264Profile: baseline # H264 level (4.0, 4.1 or 4.2).
# Software H264 level (4.0, 4.1 or 4.2) (when codec is softwareH264). rpiCameraH264Level: "4.1"
rpiCameraSoftwareH264Level: "4.1" # M-JPEG quality (0-100).
# M-JPEG JPEG quality (when codec is mjpeg).
rpiCameraMJPEGQuality: 60 rpiCameraMJPEGQuality: 60
############################################### ###############################################