Skip to content

Commit 65698a5

Browse files
committed
feat: enable libcamera selection in addition to v4l2
1 parent d566406 commit 65698a5

File tree

8 files changed

+57
-28
lines changed

8 files changed

+57
-28
lines changed

src/args.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ struct Args {
1010
int fps = 30;
1111
int width = 640;
1212
int height = 480;
13+
int cameraId = 0;
1314
int jpeg_quality = 30;
1415
int rotation_angle = 0;
1516
int sample_rate = 44100;
@@ -21,7 +22,7 @@ struct Args {
2122
bool fixed_resolution = false;
2223
uint32_t format = V4L2_PIX_FMT_MJPEG;
2324
std::string v4l2_format = "mjpeg";
24-
std::string device = "/dev/video0";
25+
std::string camera = "libcamera:0";
2526
std::string uid = "";
2627
std::string stun_url = "stun:stun.l.google.com:19302";
2728
std::string turn_url = "";

src/capturer/libcamera_capturer.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
std::shared_ptr<LibcameraCapturer> LibcameraCapturer::Create(Args args) {
88
auto ptr = std::make_shared<LibcameraCapturer>(args);
9-
ptr->Init(args.device);
9+
ptr->Init(args.cameraId);
1010
ptr->SetFps(args.fps)
1111
.SetRotation(args.rotation_angle)
1212
.SetFormat(args.width, args.height)
@@ -19,18 +19,25 @@ LibcameraCapturer::LibcameraCapturer(Args args)
1919
format_(args.format),
2020
config_(args) {}
2121

22-
void LibcameraCapturer::Init(std::string device) {
22+
void LibcameraCapturer::Init(int deviceId) {
2323
cm_ = std::make_unique<libcamera::CameraManager>();
24-
cm_->start();
24+
int ret = cm_->start();
25+
if (ret) {
26+
throw std::runtime_error("Failed to start camera manager");
27+
}
2528

26-
if (cm_->cameras().size() == 0) {
27-
ERROR_PRINT("No camera is available via libcamera.");
28-
exit(1);
29+
auto cameras = cm_->cameras();
30+
if (cameras.size() == 0) {
31+
throw std::runtime_error("No camera is available via libcamera.");
32+
}
33+
34+
if (config_.cameraId >= cameras.size()) {
35+
throw std::runtime_error("Selected camera is not available.");
2936
}
3037

31-
std::string cameraId = cm_->cameras()[0]->id();
32-
INFO_PRINT("camera id: %s", cameraId.c_str());
33-
camera_ = cm_->get(cameraId);
38+
std::string const &cam_id = cameras[config_.cameraId]->id();
39+
INFO_PRINT("camera id: %s", cam_id.c_str());
40+
camera_ = cm_->get(cam_id);
3441
camera_->acquire();
3542
camera_config_ = camera_->generateConfiguration({libcamera::StreamRole::VideoRecording});
3643
}

src/capturer/libcamera_capturer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class LibcameraCapturer : public VideoCapturer {
5656
LibcameraCapturer &SetFps(int fps);
5757
LibcameraCapturer &SetRotation(int angle);
5858

59-
void Init(std::string device);
59+
void Init(int deviceId);
6060
void AllocateBuffer();
6161
void RequestComplete(libcamera::Request *request);
6262
};

src/capturer/v4l2_capturer.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
std::shared_ptr<V4l2Capturer> V4l2Capturer::Create(Args args) {
1515
auto ptr = std::make_shared<V4l2Capturer>(args);
16-
ptr->Init(args.device);
16+
ptr->Init(args.cameraId);
1717
ptr->SetFps(args.fps)
1818
.SetRotation(args.rotation_angle)
1919
.SetFormat(args.width, args.height)
@@ -28,8 +28,9 @@ V4l2Capturer::V4l2Capturer(Args args)
2828
has_first_keyframe_(false),
2929
config_(args) {}
3030

31-
void V4l2Capturer::Init(std::string device) {
32-
fd_ = V4l2Util::OpenDevice(device.c_str());
31+
void V4l2Capturer::Init(int deviceId) {
32+
std::string devicePath = "/dev/video" + std::to_string(deviceId);
33+
fd_ = V4l2Util::OpenDevice(devicePath.c_str());
3334

3435
if (!V4l2Util::InitBuffer(fd_, &capture_, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP)) {
3536
exit(0);

src/capturer/v4l2_capturer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class V4l2Capturer : public VideoCapturer {
4747
V4l2Capturer &SetFps(int fps = 30);
4848
V4l2Capturer &SetRotation(int angle);
4949

50-
void Init(std::string device);
50+
void Init(int deviceId);
5151
bool IsCompressedFormat() const;
5252
void CaptureImage();
5353
bool CheckMatchingDevice(std::string unique_name);

src/conductor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void Conductor::InitializeTracks() {
5050
audio_track_ = peer_connection_factory_->CreateAudioTrack("audio_track", options.get());
5151
}
5252

53-
if (video_track_ == nullptr && !args.device.empty()) {
53+
if (video_track_ == nullptr && !args.camera.empty()) {
5454
video_capture_source_ = ([this]() -> std::shared_ptr<VideoCapturer> {
5555
if (args.use_libcamera) {
5656
return LibcameraCapturer::Create(args);

src/parser.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,9 @@ void Parser::ParseArgs(int argc, char *argv[], Args &args) {
3535
"The connection timeout, in seconds, after receiving a remote offer")
3636
("segment_duration", bpo::value<int>()->default_value(args.segment_duration),
3737
"The length (in seconds) of each MP4 recording.")
38-
("device", bpo::value<std::string>()->default_value(args.device),
39-
"Read the specific camera file via V4L2, default is /dev/video0")
40-
("use_libcamera", bpo::bool_switch()->default_value(args.use_libcamera),
41-
"Read YUV420 from the camera via libcamera, the `device` and `v4l2_format` "
42-
"flags will be suspended")
38+
("camera", bpo::value<std::string>()->default_value(args.camera),
39+
"Specify the camera using V4L2 or Libcamera. "
40+
"Examples: \"libcamera:0\" for Libcamera, \"v4l2:/dev/video0\" for V4L2.")
4341
("fixed_resolution", bpo::bool_switch()->default_value(args.fixed_resolution),
4442
"Disable adaptive resolution scaling and keep a fixed resolution.")
4543
("no_audio", bpo::bool_switch()->default_value(args.no_audio), "Run without audio source")
@@ -95,7 +93,7 @@ void Parser::ParseArgs(int argc, char *argv[], Args &args) {
9593
SetIfExists(vm, "rotation_angle", args.rotation_angle);
9694
SetIfExists(vm, "peer_timeout", args.peer_timeout);
9795
SetIfExists(vm, "segment_duration", args.segment_duration);
98-
SetIfExists(vm, "device", args.device);
96+
SetIfExists(vm, "camera", args.camera);
9997
SetIfExists(vm, "v4l2_format", args.v4l2_format);
10098
SetIfExists(vm, "uid", args.uid);
10199
SetIfExists(vm, "stun_url", args.stun_url);
@@ -109,7 +107,6 @@ void Parser::ParseArgs(int argc, char *argv[], Args &args) {
109107
SetIfExists(vm, "http_port", args.http_port);
110108
SetIfExists(vm, "record_path", args.record_path);
111109

112-
args.use_libcamera = vm["use_libcamera"].as<bool>();
113110
args.fixed_resolution = vm["fixed_resolution"].as<bool>();
114111
args.no_audio = vm["no_audio"].as<bool>();
115112
args.hw_accel = vm["hw_accel"].as<bool>();
@@ -134,16 +131,38 @@ void Parser::ParseArgs(int argc, char *argv[], Args &args) {
134131
}
135132
}
136133

137-
if (args.use_libcamera) {
134+
ParseDevice(args);
135+
}
136+
137+
void Parser::ParseDevice(Args &args) {
138+
size_t pos = args.camera.find(':');
139+
if (pos == std::string::npos) {
140+
throw std::runtime_error("Unknown device format: " + args.camera);
141+
}
142+
143+
std::string prefix = args.camera.substr(0, pos);
144+
std::string id = args.camera.substr(pos + 1);
145+
146+
try {
147+
args.cameraId = std::stoi(id);
148+
} catch (const std::exception &e) {
149+
throw std::runtime_error("Invalid camera ID: " + id);
150+
}
151+
152+
if (prefix == "libcamera") {
153+
args.use_libcamera = true;
138154
args.format = V4L2_PIX_FMT_YUV420;
139-
} else {
155+
std::cout << "Using Libcamera, ID: " << args.cameraId << std::endl;
156+
} else if (prefix == "v4l2") {
140157
auto it = format_map.find(args.v4l2_format);
141158
if (it != format_map.end()) {
142159
args.format = it->second;
143-
printf("Use %s format source in v4l2\n", args.v4l2_format.c_str());
160+
std::cout << "Using V4L2: " << args.v4l2_format << std::endl;
144161
} else {
145-
std::cerr << "Unsupported format: " << args.v4l2_format << std::endl;
146-
exit(1);
162+
throw std::runtime_error("Unsupported format: " + args.v4l2_format);
147163
}
164+
std::cout << "Using V4L2, ID: " << args.cameraId << std::endl;
165+
} else {
166+
throw std::runtime_error("Unknown device format: " + prefix);
148167
}
149168
}

src/parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class Parser {
77
public:
88
static void ParseArgs(int argc, char *argv[], Args &args);
9+
static void ParseDevice(Args &args);
910
};
1011

1112
#endif // PARSER_H_

0 commit comments

Comments
 (0)