Browse Source

rpicamera: add rpiCameraMode parameter (#1111)

pull/1219/head
aler9 3 years ago
parent
commit
7013b75daf
  1. 1
      internal/conf/path.go
  2. 1
      internal/core/source_static.go
  3. 4
      internal/rpicamera/exe/Makefile
  4. 84
      internal/rpicamera/exe/camera.cpp
  5. 9
      internal/rpicamera/exe/camera.h
  6. 12
      internal/rpicamera/exe/encoder.c
  7. 5
      internal/rpicamera/exe/encoder.h
  8. 12
      internal/rpicamera/exe/main.c
  9. 41
      internal/rpicamera/exe/parameters.c
  10. 16
      internal/rpicamera/exe/parameters.h
  11. 30
      internal/rpicamera/exe/roi.c
  12. 15
      internal/rpicamera/exe/roi.h
  13. 30
      internal/rpicamera/exe/sensor_mode.c
  14. 15
      internal/rpicamera/exe/sensor_mode.h
  15. 1
      internal/rpicamera/params.go
  16. 1
      internal/rpicamera/rpicamera.go
  17. 5
      rtsp-simple-server.yml

1
internal/conf/path.go

@ -67,6 +67,7 @@ type PathConf struct { @@ -67,6 +67,7 @@ type PathConf struct {
RPICameraEV float64 `json:"rpiCameraEV"`
RPICameraROI string `json:"rpiCameraROI"`
RPICameraTuningFile string `json:"rpiCameraTuningFile"`
RPICameraMode string `json:"rpiCameraMode"`
RPICameraFPS int `json:"rpiCameraFPS"`
RPICameraIDRPeriod int `json:"rpiCameraIDRPeriod"`
RPICameraBitrate int `json:"rpiCameraBitrate"`

1
internal/core/source_static.go

@ -104,6 +104,7 @@ func newSourceStatic( @@ -104,6 +104,7 @@ func newSourceStatic(
EV: conf.RPICameraEV,
ROI: conf.RPICameraROI,
TuningFile: conf.RPICameraTuningFile,
Mode: conf.RPICameraMode,
FPS: conf.RPICameraFPS,
IDRPeriod: conf.RPICameraIDRPeriod,
Bitrate: conf.RPICameraBitrate,

4
internal/rpicamera/exe/Makefile

@ -26,7 +26,9 @@ OBJS = \ @@ -26,7 +26,9 @@ OBJS = \
camera.o \
encoder.o \
main.o \
parameters.o
parameters.o \
roi.o \
sensor_mode.o
all: exe

84
internal/rpicamera/exe/camera.cpp

@ -46,11 +46,32 @@ const char *camera_get_error() { @@ -46,11 +46,32 @@ const char *camera_get_error() {
return errbuf;
}
// https://github.com/raspberrypi/libcamera-apps/blob/dd97618a25523c2c4aa58f87af5f23e49aa6069c/core/libcamera_app.cpp#L42
static libcamera::PixelFormat mode_to_pixel_format(sensor_mode_t *mode) {
static std::vector<std::pair<std::pair<int, bool>, libcamera::PixelFormat>> table = {
{ {8, false}, libcamera::formats::SBGGR8 },
{ {8, true}, libcamera::formats::SBGGR8 },
{ {10, false}, libcamera::formats::SBGGR10 },
{ {10, true}, libcamera::formats::SBGGR10_CSI2P },
{ {12, false}, libcamera::formats::SBGGR12 },
{ {12, true}, libcamera::formats::SBGGR12_CSI2P },
};
auto it = std::find_if(table.begin(), table.end(), [&mode] (auto &m) {
return mode->bit_depth == m.first.first && mode->packed == m.first.second; });
if (it != table.end()) {
return it->second;
}
return libcamera::formats::SBGGR12_CSI2P;
}
struct CameraPriv {
parameters_t *params;
camera_frame_cb frame_cb;
std::unique_ptr<CameraManager> camera_manager;
std::shared_ptr<Camera> camera;
Stream *video_stream;
std::unique_ptr<FrameBufferAllocator> allocator;
std::vector<std::unique_ptr<Request>> requests;
};
@ -87,6 +108,8 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca @@ -87,6 +108,8 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca
return false;
}
setenv("LIBCAMERA_RPI_TUNING_FILE", params->tuning_file, 1);
ret = camp->camera->acquire();
if (ret != 0) {
set_error("Camera.acquire() failed");
@ -94,21 +117,32 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca @@ -94,21 +117,32 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca
}
StreamRoles stream_roles = { StreamRole::VideoRecording };
if (params->mode != NULL) {
stream_roles.push_back(StreamRole::Raw);
}
std::unique_ptr<CameraConfiguration> conf = camp->camera->generateConfiguration(stream_roles);
if (conf == NULL) {
set_error("Camera.generateConfiguration() failed");
return false;
}
StreamConfiguration &stream_conf = conf->at(0);
stream_conf.pixelFormat = formats::YUV420;
stream_conf.bufferCount = params->buffer_count;
stream_conf.size.width = params->width;
stream_conf.size.height = params->height;
StreamConfiguration &video_stream_conf = conf->at(0);
video_stream_conf.pixelFormat = formats::YUV420;
video_stream_conf.bufferCount = params->buffer_count;
video_stream_conf.size.width = params->width;
video_stream_conf.size.height = params->height;
if (params->width >= 1280 || params->height >= 720) {
stream_conf.colorSpace = libcamera::ColorSpace::Rec709;
video_stream_conf.colorSpace = libcamera::ColorSpace::Rec709;
} else {
stream_conf.colorSpace = libcamera::ColorSpace::Smpte170m;
video_stream_conf.colorSpace = libcamera::ColorSpace::Smpte170m;
}
if (params->mode != NULL) {
StreamConfiguration &raw_stream_conf = conf->at(1);
raw_stream_conf.size = libcamera::Size(params->mode->width, params->mode->height);
raw_stream_conf.pixelFormat = mode_to_pixel_format(params->mode);
raw_stream_conf.bufferCount = video_stream_conf.bufferCount;
}
conf->transform = Transform::Identity;
@ -119,8 +153,6 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca @@ -119,8 +153,6 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca
conf->transform = Transform::VFlip * conf->transform;
}
setenv("LIBCAMERA_RPI_TUNING_FILE", params->tuning_file, 1);
CameraConfiguration::Status vstatus = conf->validate();
if (vstatus == CameraConfiguration::Invalid) {
set_error("StreamConfiguration.validate() failed");
@ -133,23 +165,23 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca @@ -133,23 +165,23 @@ bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **ca
return false;
}
Stream *stream = stream_conf.stream();
camp->video_stream = video_stream_conf.stream();
camp->allocator = std::make_unique<FrameBufferAllocator>(camp->camera);
res = camp->allocator->allocate(stream);
res = camp->allocator->allocate(camp->video_stream);
if (res < 0) {
set_error("allocate() failed");
return false;
}
for (const std::unique_ptr<FrameBuffer> &buffer : camp->allocator->buffers(stream)) {
for (const std::unique_ptr<FrameBuffer> &buffer : camp->allocator->buffers(camp->video_stream)) {
std::unique_ptr<Request> request = camp->camera->createRequest((uint64_t)camp.get());
if (request == NULL) {
set_error("createRequest() failed");
return false;
}
int res = request->addBuffer(stream, buffer.get());
int res = request->addBuffer(camp->video_stream, buffer.get());
if (res != 0) {
set_error("addBuffer() failed");
return false;
@ -185,14 +217,14 @@ static void on_request_complete(Request *request) { @@ -185,14 +217,14 @@ static void on_request_complete(Request *request) {
camp->camera->queueRequest(request);
}
int camera_get_stride(camera_t *cam) {
int camera_get_mode_stride(camera_t *cam) {
CameraPriv *camp = (CameraPriv *)cam;
return (*camp->camera->streams().begin())->configuration().stride;
return camp->video_stream->configuration().stride;
}
int camera_get_colorspace(camera_t *cam) {
int camera_get_mode_colorspace(camera_t *cam) {
CameraPriv *camp = (CameraPriv *)cam;
return get_v4l2_colorspace((*camp->camera->streams().begin())->configuration().colorSpace);
return get_v4l2_colorspace(camp->video_stream->configuration().colorSpace);
}
bool camera_start(camera_t *cam) {
@ -271,21 +303,13 @@ bool camera_start(camera_t *cam) { @@ -271,21 +303,13 @@ bool camera_start(camera_t *cam) {
ctrls.set(controls::ExposureValue, camp->params->ev);
if (strlen(camp->params->roi) != 0) {
float vals[4];
int i = 0;
char *token = strtok((char *)camp->params->roi, ",");
while (token != NULL) {
vals[i++] = atof(token);
token = strtok(NULL, ",");
}
if (camp->params->roi != NULL) {
Rectangle sensor_area = camp->camera->properties().get(libcamera::properties::ScalerCropMaximum);
Rectangle crop(
vals[0] * sensor_area.width,
vals[1] * sensor_area.height,
vals[2] * sensor_area.width,
vals[3] * sensor_area.height);
camp->params->roi->x * sensor_area.width,
camp->params->roi->y * sensor_area.height,
camp->params->roi->width * sensor_area.width,
camp->params->roi->height * sensor_area.height);
crop.translateBy(sensor_area.topLeft());
ctrls.set(controls::ScalerCrop, crop);
}

9
internal/rpicamera/exe/camera.h

@ -1,3 +1,6 @@ @@ -1,3 +1,6 @@
#ifndef __CAMERA_H__
#define __CAMERA_H__
typedef void camera_t;
typedef void (*camera_frame_cb)(int buffer_fd, uint64_t size, uint64_t timestamp);
@ -8,10 +11,12 @@ extern "C" { @@ -8,10 +11,12 @@ extern "C" {
const char *camera_get_error();
bool camera_create(parameters_t *params, camera_frame_cb frame_cb, camera_t **cam);
int camera_get_stride(camera_t *cam);
int camera_get_colorspace(camera_t *cam);
int camera_get_mode_stride(camera_t *cam);
int camera_get_mode_colorspace(camera_t *cam);
bool camera_start(camera_t *cam);
#ifdef __cplusplus
}
#endif
#endif

12
internal/rpicamera/exe/encoder.c

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
#include "parameters.h"
#include "encoder.h"
#define DEVICE "/dev/video11"
char errbuf[256];
static void set_error(const char *format, ...) {
@ -58,7 +60,7 @@ static void *output_thread(void *userdata) { @@ -58,7 +60,7 @@ static void *output_thread(void *userdata) {
buf.m.planes = planes;
int res = ioctl(encp->fd, VIDIOC_DQBUF, &buf);
if (res != 0) {
fprintf(stderr, "output_thread(): ioctl() failed\n");
fprintf(stderr, "output_thread(): ioctl(VIDIOC_DQBUF) failed\n");
exit(1);
}
@ -88,7 +90,7 @@ static void *output_thread(void *userdata) { @@ -88,7 +90,7 @@ static void *output_thread(void *userdata) {
buf.m.planes[0].length = length;
int res = ioctl(encp->fd, VIDIOC_QBUF, &buf);
if (res < 0) {
fprintf(stderr, "output_thread(): ioctl() failed\n");
fprintf(stderr, "output_thread(): ioctl(VIDIOC_QBUF) failed\n");
exit(1);
}
}
@ -102,7 +104,7 @@ bool encoder_create(parameters_t *params, int stride, int colorspace, encoder_ou @@ -102,7 +104,7 @@ bool encoder_create(parameters_t *params, int stride, int colorspace, encoder_ou
*enc = malloc(sizeof(encoder_priv_t));
encoder_priv_t *encp = (encoder_priv_t *)(*enc);
encp->fd = open("/dev/video11", O_RDWR, 0);
encp->fd = open(DEVICE, O_RDWR, 0);
if (encp->fd < 0) {
set_error("unable to open device");
return false;
@ -254,7 +256,7 @@ bool encoder_create(parameters_t *params, int stride, int colorspace, encoder_ou @@ -254,7 +256,7 @@ bool encoder_create(parameters_t *params, int stride, int colorspace, encoder_ou
res = ioctl(encp->fd, VIDIOC_QBUF, &buffer);
if (res != 0) {
set_error("ioctl() failed");
set_error("ioctl(VIDIOC_QBUF) failed");
free(encp->capture_buffers);
close(encp->fd);
return false;
@ -309,7 +311,7 @@ void encoder_encode(encoder_t *enc, int buffer_fd, size_t size, int64_t timestam @@ -309,7 +311,7 @@ void encoder_encode(encoder_t *enc, int buffer_fd, size_t size, int64_t timestam
buf.m.planes[0].length = size;
int res = ioctl(encp->fd, VIDIOC_QBUF, &buf);
if (res != 0) {
fprintf(stderr, "encoder_encode(): ioctl() failed\n");
fprintf(stderr, "encoder_encode(): ioctl(VIDIOC_QBUF) failed\n");
exit(1);
}
}

5
internal/rpicamera/exe/encoder.h

@ -1,3 +1,6 @@ @@ -1,3 +1,6 @@
#ifndef __ENCODER_H__
#define __ENCODER_H__
typedef void encoder_t;
typedef void (*encoder_output_cb)(const uint8_t *buf, uint64_t size);
@ -5,3 +8,5 @@ typedef void (*encoder_output_cb)(const uint8_t *buf, uint64_t size); @@ -5,3 +8,5 @@ typedef void (*encoder_output_cb)(const uint8_t *buf, uint64_t size);
const char *encoder_get_error();
bool encoder_create(parameters_t *params, int stride, int colorspace, encoder_output_cb output_cb, encoder_t **enc);
void encoder_encode(encoder_t *enc, int buffer_fd, size_t size, int64_t timestamp_us);
#endif

12
internal/rpicamera/exe/main.c

@ -72,9 +72,13 @@ int main() { @@ -72,9 +72,13 @@ int main() {
pthread_mutex_init(&pipe_mutex, NULL);
pthread_mutex_lock(&pipe_mutex);
parameters_load(&params);
bool ok = parameters_load(&params);
if (!ok) {
pipe_write_error(pipe_fd, "parameters_load(): %s", parameters_get_error());
return 5;
}
bool ok = camera_create(
ok = camera_create(
&params,
on_frame,
&cam);
@ -85,8 +89,8 @@ int main() { @@ -85,8 +89,8 @@ int main() {
ok = encoder_create(
&params,
camera_get_stride(cam),
camera_get_colorspace(cam),
camera_get_mode_stride(cam),
camera_get_mode_colorspace(cam),
on_encoder_output,
&enc);
if (!ok) {

41
internal/rpicamera/exe/parameters.c

@ -1,12 +1,26 @@ @@ -1,12 +1,26 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdio.h>
#include <linux/videodev2.h>
#include "parameters.h"
void parameters_load(parameters_t *params) {
char errbuf[256];
static void set_error(const char *format, ...) {
va_list args;
va_start(args, format);
vsnprintf(errbuf, 256, format, args);
}
const char *parameters_get_error() {
return errbuf;
}
bool parameters_load(parameters_t *params) {
params->camera_id = atoi(getenv("CAMERA_ID"));
params->width = atoi(getenv("WIDTH"));
params->height = atoi(getenv("HEIGHT"));
@ -23,8 +37,29 @@ void parameters_load(parameters_t *params) { @@ -23,8 +37,29 @@ void parameters_load(parameters_t *params) {
params->metering = getenv("METERING");
params->gain = atof(getenv("GAIN"));
params->ev = atof(getenv("EV"));
params->roi = getenv("ROI");
if (strlen(getenv("ROI")) != 0) {
bool ok = roi_load(getenv("ROI"), &params->roi);
if (!ok) {
set_error("invalid ROI");
return false;
}
} else {
params->roi = NULL;
}
params->tuning_file = getenv("TUNING_FILE");
if (strlen(getenv("MODE")) != 0) {
bool ok = sensor_mode_load(getenv("MODE"), &params->mode);
if (!ok) {
set_error("invalid sensor mode");
return false;
}
} else {
params->mode = NULL;
}
params->fps = atoi(getenv("FPS"));
params->idr_period = atoi(getenv("IDR_PERIOD"));
params->bitrate = atoi(getenv("BITRATE"));
@ -49,4 +84,6 @@ void parameters_load(parameters_t *params) { @@ -49,4 +84,6 @@ void parameters_load(parameters_t *params) {
params->buffer_count = 3;
params->capture_buffer_count = params->buffer_count * 2;
return true;
}

16
internal/rpicamera/exe/parameters.h

@ -1,3 +1,11 @@ @@ -1,3 +1,11 @@
#ifndef __PARAMETERS_H__
#define __PARAMETERS_H__
#include <stdbool.h>
#include "roi.h"
#include "sensor_mode.h"
typedef struct {
unsigned int camera_id;
unsigned int width;
@ -15,8 +23,9 @@ typedef struct { @@ -15,8 +23,9 @@ typedef struct {
const char *metering;
float gain;
float ev;
const char *roi;
roi_t *roi;
const char *tuning_file;
sensor_mode_t *mode;
unsigned int fps;
unsigned int idr_period;
unsigned int bitrate;
@ -32,8 +41,11 @@ typedef struct { @@ -32,8 +41,11 @@ typedef struct {
extern "C" {
#endif
void parameters_load(parameters_t *params);
const char *parameters_get_error();
bool parameters_load(parameters_t *params);
#ifdef __cplusplus
}
#endif
#endif

30
internal/rpicamera/exe/roi.c

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
#include <stdlib.h>
#include <string.h>
#include "roi.h"
bool roi_load(const char *encoded, roi_t **mode) {
float vals[4];
int i = 0;
char *token = strtok((char *)encoded, ",");
while (token != NULL) {
vals[i] = atof(token);
if (vals[i] < 0 || vals[i] > 1) {
return false;
}
i++;
token = strtok(NULL, ",");
}
if (i != 4) {
return false;
}
*mode = malloc(sizeof(roi_t));
(*mode)->x = vals[0];
(*mode)->y = vals[1];
(*mode)->width = vals[2];
(*mode)->height = vals[3];
return true;
}

15
internal/rpicamera/exe/roi.h

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
#ifndef __ROI_H__
#define __ROI_H__
#include <stdbool.h>
typedef struct {
float x;
float y;
float width;
float height;
} roi_t;
bool roi_load(const char *encoded, roi_t **mode);
#endif

30
internal/rpicamera/exe/sensor_mode.c

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "sensor_mode.h"
bool sensor_mode_load(const char *encoded, sensor_mode_t **mode) {
*mode = malloc(sizeof(sensor_mode_t));
char p;
int n = sscanf(encoded, "%u:%u:%u:%c", &((*mode)->width), &((*mode)->height), &((*mode)->bit_depth), &p);
if (n < 2) {
free(*mode);
return false;
}
if (n < 4) {
(*mode)->packed = true;
} else if (toupper(p) == 'P') {
(*mode)->packed = true;
} else if (toupper(p) == 'U') {
(*mode)->packed = false;
}
if (n < 3) {
(*mode)->bit_depth = 12;
}
return true;
}

15
internal/rpicamera/exe/sensor_mode.h

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
#ifndef __SENSOR_MODE_H__
#define __SENSOR_MODE_H__
#include <stdbool.h>
typedef struct {
int width;
int height;
int bit_depth;
bool packed;
} sensor_mode_t;
bool sensor_mode_load(const char *encoded, sensor_mode_t **mode);
#endif

1
internal/rpicamera/params.go

@ -20,6 +20,7 @@ type Params struct { @@ -20,6 +20,7 @@ type Params struct {
EV float64
ROI string
TuningFile string
Mode string
FPS int
IDRPeriod int
Bitrate int

1
internal/rpicamera/rpicamera.go

@ -60,6 +60,7 @@ func New( @@ -60,6 +60,7 @@ func New(
"EV=" + strconv.FormatFloat(params.EV, 'f', -1, 64),
"ROI=" + params.ROI,
"TUNING_FILE=" + params.TuningFile,
"MODE=" + params.Mode,
"FPS=" + strconv.FormatInt(int64(params.FPS), 10),
"IDR_PERIOD=" + strconv.FormatInt(int64(params.IDRPeriod), 10),
"BITRATE=" + strconv.FormatInt(int64(params.Bitrate), 10),

5
rtsp-simple-server.yml

@ -264,10 +264,13 @@ paths: @@ -264,10 +264,13 @@ paths:
rpiCameraGain: 0
# EV compensation of the image [-10, 10]
rpiCameraEV: 0
# Region of interst in format x,y,width,height
# Region of interest, in format x,y,width,height
rpiCameraROI:
# tuning file
rpiCameraTuningFile:
# sensor mode, in format [width]:[height]:[bit-depth]:[packing]
# bit-depth and packing are optional.
rpiCameraMode:
# frames per second
rpiCameraFPS: 30
# period between IDR frames

Loading…
Cancel
Save