Skip to content

Commit 598ece6

Browse files
committed
feat: add a record mode flag
1 parent 0cb6944 commit 598ece6

File tree

4 files changed

+51
-18
lines changed

4 files changed

+51
-18
lines changed

src/args.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ struct Args {
9999
bool set_default_lens_position = false;
100100

101101
// recording
102+
std::string record = "both";
103+
int record_mode = -1;
102104
std::string record_path = "";
103105
int file_duration = 60;
104106

src/parser.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "parser.h"
2+
#include "recorder/recorder_manager.h"
23
#include "rtc/rtc_peer.h"
34

45
#include <algorithm>
@@ -16,6 +17,12 @@ static const std::unordered_map<std::string, int> v4l2_fmt_table = {
1617
{"yuyv", V4L2_PIX_FMT_YUYV},
1718
};
1819

20+
static const std::unordered_map<std::string, int> record_mode_table = {
21+
{"both", -1},
22+
{"video", RecordMode::Video},
23+
{"snapshot", RecordMode::Snapshot},
24+
};
25+
1926
static const std::unordered_map<std::string, int> ipc_mode_table = {
2027
{"both", -1},
2128
{"lossy", ChannelMode::Lossy},
@@ -133,11 +140,14 @@ void Parser::ParseArgs(int argc, char *argv[], Args &args) {
133140
"Autofocus window as x,y,width,height. e.g. '0.3,0.3,0.4,0.4'")
134141
("lens-position", bpo::value<std::string>(&args.lens_position_)->default_value(args.lens_position_),
135142
"Set the lens to a particular focus position, \"0\" moves the lens to infinity, or \"default\" for the hyperfocal distance")
143+
("record-mode", bpo::value<std::string>(&args.record)->default_value(args.record),
144+
"Recording mode: 'video' to record MP4 files, 'snapshot' to save periodic JPEG images, "
145+
"or 'both' to do both simultaneously.")
136146
("record-path", bpo::value<std::string>(&args.record_path)->default_value(args.record_path),
137147
"Set the path where recording video files will be saved. "
138148
"If the value is empty or unavailable, the recorder will not start.")
139149
("file-duration", bpo::value<int>(&args.file_duration)->default_value(args.file_duration),
140-
"The length (in seconds) of each MP4 recording.")
150+
"The duration (in seconds) of each video file, or the interval between snapshots.")
141151
("jpeg-quality", bpo::value<int>(&args.jpeg_quality)->default_value(args.jpeg_quality),
142152
"Set the quality of the snapshot and thumbnail images in range 0 to 100.")
143153
("peer-timeout", bpo::value<int>(&args.peer_timeout)->default_value(args.peer_timeout),
@@ -262,6 +272,7 @@ void Parser::ParseArgs(int argc, char *argv[], Args &args) {
262272

263273
args.jpeg_quality = std::clamp(args.jpeg_quality, 0, 100);
264274

275+
args.record_mode = ParseEnum(record_mode_table, args.record);
265276
args.ipc_channel_mode = ParseEnum(ipc_mode_table, args.ipc_channel);
266277

267278
ParseDevice(args);

src/recorder/recorder_manager.cpp

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ void RecorderManager::CreateVideoRecorder(std::shared_ptr<VideoCapturer> capture
8585
fps = capturer->fps();
8686
width = capturer->width();
8787
height = capturer->height();
88-
video_recorder = ([capturer]() -> std::unique_ptr<VideoRecorder> {
89-
if (capturer->format() == V4L2_PIX_FMT_H264) {
88+
video_recorder = ([this, capturer]() -> std::unique_ptr<VideoRecorder> {
89+
if (config.record_mode == RecordMode::Snapshot) {
90+
return nullptr;
91+
} else if (capturer->format() == V4L2_PIX_FMT_H264) {
9092
return RawH264Recorder::Create(capturer->config());
9193
} else {
9294
return H264Recorder::Create(capturer->config());
@@ -95,8 +97,12 @@ void RecorderManager::CreateVideoRecorder(std::shared_ptr<VideoCapturer> capture
9597
}
9698

9799
void RecorderManager::CreateAudioRecorder(std::shared_ptr<PaCapturer> capturer) {
98-
audio_recorder = ([capturer]() -> std::unique_ptr<AudioRecorder> {
99-
return AudioRecorder::Create(capturer->config());
100+
audio_recorder = ([this, capturer]() -> std::unique_ptr<AudioRecorder> {
101+
if (config.record_mode == RecordMode::Snapshot) {
102+
return nullptr;
103+
} else {
104+
return AudioRecorder::Create(capturer->config());
105+
}
100106
})();
101107
}
102108

@@ -126,20 +132,27 @@ void RecorderManager::SubscribeVideoSource(std::shared_ptr<VideoCapturer> video_
126132

127133
if (has_first_keyframe && video_recorder) {
128134
video_recorder->OnBuffer(buffer);
129-
elapsed_time_ = (buffer->timestamp().tv_sec - last_created_time_.tv_sec) +
130-
(buffer->timestamp().tv_usec - last_created_time_.tv_usec) / 1000000.0;
131135
}
132-
});
133136

134-
video_recorder->OnPacketed([this](AVPacket *pkt) {
135-
this->WriteIntoFile(pkt);
137+
elapsed_time_ = (buffer->timestamp().tv_sec - last_created_time_.tv_sec) +
138+
(buffer->timestamp().tv_usec - last_created_time_.tv_usec) / 1000000.0;
136139
});
140+
141+
if (video_recorder) {
142+
video_recorder->OnPacketed([this](AVPacket *pkt) {
143+
this->WriteIntoFile(pkt);
144+
});
145+
}
137146
}
138147

139148
void RecorderManager::SubscribeAudioSource(std::shared_ptr<PaCapturer> audio_src) {
149+
if (!audio_recorder) {
150+
return;
151+
}
152+
140153
audio_observer = audio_src->AsObservable();
141154
audio_observer->Subscribe([this](PaBuffer buffer) {
142-
if (has_first_keyframe && audio_recorder) {
155+
if (has_first_keyframe) {
143156
audio_recorder->OnBuffer(buffer);
144157
}
145158
});
@@ -171,7 +184,7 @@ void RecorderManager::Start() {
171184
auto folder = new_file.GetFolderPath();
172185
Utils::CreateFolder(folder);
173186

174-
{
187+
if (config.record_mode != RecordMode::Snapshot) {
175188
std::lock_guard<std::mutex> lock(ctx_mux);
176189
fmt_ctx = RecUtil::CreateContainer(new_file.GetFullPath());
177190
if (fmt_ctx == nullptr) {
@@ -198,7 +211,10 @@ void RecorderManager::Start() {
198211
audio_recorder->Start();
199212
}
200213

201-
MakePreviewImage();
214+
if (config.record_mode != RecordMode::Video) {
215+
auto image_path = ReplaceExtension(new_file.GetFullPath(), PREVIEW_IMAGE_EXTENSION);
216+
MakePreviewImage(image_path);
217+
}
202218

203219
has_first_keyframe = true;
204220
}
@@ -228,15 +244,14 @@ RecorderManager::~RecorderManager() {
228244
audio_observer.reset();
229245
}
230246

231-
void RecorderManager::MakePreviewImage() {
232-
std::thread([this]() {
247+
void RecorderManager::MakePreviewImage(std::string path) {
248+
std::thread([this, path]() {
233249
std::this_thread::sleep_for(std::chrono::seconds(3));
234250
if (video_src_ == nullptr) {
235251
return;
236252
}
237253
auto i420buff = video_src_->GetI420Frame();
238-
Utils::CreateJpegImage(i420buff->DataY(), i420buff->width(), i420buff->height(),
239-
ReplaceExtension(fmt_ctx->url, PREVIEW_IMAGE_EXTENSION),
254+
Utils::CreateJpegImage(i420buff->DataY(), i420buff->width(), i420buff->height(), path,
240255
config.jpeg_quality);
241256
}).detach();
242257
}

src/recorder/recorder_manager.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ extern "C" {
1616
#include "recorder/audio_recorder.h"
1717
#include "recorder/video_recorder.h"
1818

19+
enum RecordMode {
20+
Video,
21+
Snapshot
22+
};
23+
1924
class RecUtil {
2025
public:
2126
static AVFormatContext *CreateContainer(const std::string &full_path);
@@ -60,7 +65,7 @@ class RecorderManager {
6065
struct timeval last_created_time_;
6166
std::shared_ptr<VideoCapturer> video_src_;
6267

63-
void MakePreviewImage();
68+
void MakePreviewImage(std::string path);
6469
std::string ReplaceExtension(const std::string &url, const std::string &new_extension);
6570
};
6671

0 commit comments

Comments
 (0)