From 6d342082c2e202cb7b3f84ed3a8ab37b2422e85d Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Wed, 19 Jul 2023 14:55:21 +0200 Subject: [PATCH] rpi camera: add rpiCameraHDR parameter (#1876) (#2083) --- apidocs/openapi.yaml | 2 ++ internal/conf/path.go | 1 + internal/core/rpicamera_source.go | 1 + internal/rpicamera/exe/camera.cpp | 22 ++++++++++++++ internal/rpicamera/exe/parameters.c | 2 ++ internal/rpicamera/exe/parameters.h | 1 + internal/rpicamera/params.go | 45 +++++++++++++++++++++++++++++ internal/rpicamera/rpicamera.go | 43 ++------------------------- mediamtx.yml | 2 ++ 9 files changed, 78 insertions(+), 41 deletions(-) diff --git a/apidocs/openapi.yaml b/apidocs/openapi.yaml index a354a324..c8cdc934 100644 --- a/apidocs/openapi.yaml +++ b/apidocs/openapi.yaml @@ -264,6 +264,8 @@ components: type: number rpiCameraROI: type: string + rpiCameraHDR: + type: boolean rpiCameraTuningFile: type: string rpiCameraMode: diff --git a/internal/conf/path.go b/internal/conf/path.go index 2d9f7430..9c46597b 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -90,6 +90,7 @@ type PathConf struct { RPICameraGain float64 `json:"rpiCameraGain"` RPICameraEV float64 `json:"rpiCameraEV"` RPICameraROI string `json:"rpiCameraROI"` + RPICameraHDR bool `json:"rpiCameraHDR"` RPICameraTuningFile string `json:"rpiCameraTuningFile"` RPICameraMode string `json:"rpiCameraMode"` RPICameraFPS float64 `json:"rpiCameraFPS"` diff --git a/internal/core/rpicamera_source.go b/internal/core/rpicamera_source.go index d492f478..e292c5e6 100644 --- a/internal/core/rpicamera_source.go +++ b/internal/core/rpicamera_source.go @@ -32,6 +32,7 @@ func paramsFromConf(cnf *conf.PathConf) rpicamera.Params { Gain: cnf.RPICameraGain, EV: cnf.RPICameraEV, ROI: cnf.RPICameraROI, + HDR: cnf.RPICameraHDR, TuningFile: cnf.RPICameraTuningFile, Mode: cnf.RPICameraMode, FPS: cnf.RPICameraFPS, diff --git a/internal/rpicamera/exe/camera.cpp b/internal/rpicamera/exe/camera.cpp index e5a9445a..e9586b46 100644 --- a/internal/rpicamera/exe/camera.cpp +++ b/internal/rpicamera/exe/camera.cpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include #include @@ -105,7 +108,26 @@ static uint8_t *map_buffer(FrameBuffer *buffer) { return NULL; } +// https://github.com/raspberrypi/libcamera-apps/blob/a6267d51949d0602eedf60f3ddf8c6685f652812/core/options.cpp#L101 +static void set_hdr(bool hdr) { + bool ok = false; + for (int i = 0; i < 4 && !ok; i++) + { + std::string dev("/dev/v4l-subdev"); + dev += (char)('0' + i); + int fd = open(dev.c_str(), O_RDWR, 0); + if (fd < 0) + continue; + + v4l2_control ctrl { V4L2_CID_WIDE_DYNAMIC_RANGE, hdr }; + ok = !ioctl(fd, VIDIOC_S_CTRL, &ctrl); + close(fd); + } +} + bool camera_create(const parameters_t *params, camera_frame_cb frame_cb, camera_t **cam) { + set_hdr(params->hdr); + // We make sure to set the environment variable before libcamera init setenv("LIBCAMERA_RPI_TUNING_FILE", params->tuning_file, 1); diff --git a/internal/rpicamera/exe/parameters.c b/internal/rpicamera/exe/parameters.c index 4fe15cbe..8b9b0715 100644 --- a/internal/rpicamera/exe/parameters.c +++ b/internal/rpicamera/exe/parameters.c @@ -81,6 +81,8 @@ bool parameters_unserialize(parameters_t *params, const uint8_t *buf, size_t buf } } free(decoded_val); + } else if (strcmp(key, "HDR") == 0) { + params->hdr = (strcmp(val, "1") == 0); } else if (strcmp(key, "TuningFile") == 0) { params->tuning_file = base64_decode(val); } else if (strcmp(key, "Mode") == 0) { diff --git a/internal/rpicamera/exe/parameters.h b/internal/rpicamera/exe/parameters.h index e9b6caee..2b19a942 100644 --- a/internal/rpicamera/exe/parameters.h +++ b/internal/rpicamera/exe/parameters.h @@ -25,6 +25,7 @@ typedef struct { float gain; float ev; window_t *roi; + bool hdr; char *tuning_file; sensor_mode_t *mode; float fps; diff --git a/internal/rpicamera/params.go b/internal/rpicamera/params.go index 029ac20c..c8ff1e73 100644 --- a/internal/rpicamera/params.go +++ b/internal/rpicamera/params.go @@ -1,5 +1,12 @@ package rpicamera +import ( + "encoding/base64" + "reflect" + "strconv" + "strings" +) + // Params is a set of camera parameters. type Params struct { CameraID int @@ -19,6 +26,7 @@ type Params struct { Gain float64 EV float64 ROI string + HDR bool TuningFile string Mode string FPS float64 @@ -34,3 +42,40 @@ type Params struct { TextOverlayEnable bool TextOverlay string } + +func (p Params) serialize() []byte { //nolint:unused + rv := reflect.ValueOf(p) + rt := rv.Type() + nf := rv.NumField() + ret := make([]string, nf) + + for i := 0; i < nf; i++ { + entry := rt.Field(i).Name + ":" + f := rv.Field(i) + + switch f.Kind() { + case reflect.Int: + entry += strconv.FormatInt(f.Int(), 10) + + case reflect.Float64: + entry += strconv.FormatFloat(f.Float(), 'f', -1, 64) + + case reflect.String: + entry += base64.StdEncoding.EncodeToString([]byte(f.String())) + + case reflect.Bool: + if f.Bool() { + entry += "1" + } else { + entry += "0" + } + + default: + panic("unhandled type") + } + + ret[i] = entry + } + + return []byte(strings.Join(ret, " ")) +} diff --git a/internal/rpicamera/rpicamera.go b/internal/rpicamera/rpicamera.go index 49debbe9..c9b288c9 100644 --- a/internal/rpicamera/rpicamera.go +++ b/internal/rpicamera/rpicamera.go @@ -6,11 +6,9 @@ package rpicamera import ( "debug/elf" _ "embed" - "encoding/base64" "fmt" "os" "os/exec" - "reflect" "runtime" "strconv" "strings" @@ -50,43 +48,6 @@ func startEmbeddedExe(content []byte, env []string) (*exec.Cmd, error) { return cmd, nil } -func serializeParams(p Params) []byte { - rv := reflect.ValueOf(p) - rt := rv.Type() - nf := rv.NumField() - ret := make([]string, nf) - - for i := 0; i < nf; i++ { - entry := rt.Field(i).Name + ":" - f := rv.Field(i) - - switch f.Kind() { - case reflect.Int: - entry += strconv.FormatInt(f.Int(), 10) - - case reflect.Float64: - entry += strconv.FormatFloat(f.Float(), 'f', -1, 64) - - case reflect.String: - entry += base64.StdEncoding.EncodeToString([]byte(f.String())) - - case reflect.Bool: - if f.Bool() { - entry += "1" - } else { - entry += "0" - } - - default: - panic("unhandled type") - } - - ret[i] = entry - } - - return []byte(strings.Join(ret, " ")) -} - func findLibrary(name string) (string, error) { byts, err := exec.Command("ldconfig", "-p").Output() if err == nil { @@ -220,7 +181,7 @@ func New( return nil, err } - c.pipeConf.write(append([]byte{'c'}, serializeParams(params)...)) + c.pipeConf.write(append([]byte{'c'}, params.serialize()...)) c.waitDone = make(chan error) go func() { @@ -266,7 +227,7 @@ func (c *RPICamera) Close() { } func (c *RPICamera) ReloadParams(params Params) { - c.pipeConf.write(append([]byte{'c'}, serializeParams(params)...)) + c.pipeConf.write(append([]byte{'c'}, params.serialize()...)) } func (c *RPICamera) readReady() error { diff --git a/mediamtx.yml b/mediamtx.yml index b1fb444c..4a9cfef6 100644 --- a/mediamtx.yml +++ b/mediamtx.yml @@ -366,6 +366,8 @@ paths: rpiCameraEV: 0 # Region of interest, in format x,y,width,height rpiCameraROI: + # whether to enable HDR on Raspberry Camera 3. + rpiCameraHDR: false # tuning file rpiCameraTuningFile: # sensor mode, in format [width]:[height]:[bit-depth]:[packing]