Skip to content

Commit b2d1155

Browse files
authored
Update video recording configuration to improve record video quality (#283)
1 parent e5899be commit b2d1155

File tree

3 files changed

+46
-60
lines changed

3 files changed

+46
-60
lines changed

Lux/lux_react/src/lux.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

Lux/src/video_recorder.cpp

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,12 @@ bool VideoRecorder::initialize_video()
104104
codec_context->time_base = AVRational{1, options.fps};
105105
codec_context->framerate = AVRational{options.fps, 1};
106106

107-
// MOBILE COMPATIBILITY: Set adaptive GOP size based on resolution
108107
// This will be used for keyframe forcing and must match the keyint setting
108+
bool isFullHD = (options.width >= 1920 || options.height >= 1080);
109109
bool isHighRes = (options.width >= 1280 || options.height >= 720);
110110
bool isLowRes = (options.width <= 640 && options.height <= 480);
111-
codec_context->gop_size = isHighRes ? 60 : isLowRes ? 15 : 30;
112-
111+
codec_context->gop_size = isFullHD ? 90 : isHighRes ? 60 : isLowRes ? 15 : 30;
112+
113113
codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
114114
codec_context->bit_rate = options.bitrate;
115115

@@ -121,71 +121,72 @@ bool VideoRecorder::initialize_video()
121121

122122
if (codec_context->codec_id == AV_CODEC_ID_H264)
123123
{
124+
bool isFullHD = (options.width >= 1920 || options.height >= 1080);
125+
if (isFullHD) {
126+
av_opt_set(codec_context->priv_data, "profile", "main", 0);
127+
av_opt_set(codec_context->priv_data, "level", "4.1", 0);
128+
av_opt_set_int(codec_context->priv_data, "refs", 2, 0);
129+
av_opt_set_int(codec_context->priv_data, "b-frames", 0, 0);
130+
} else {
131+
av_opt_set(codec_context->priv_data, "profile", "baseline", 0);
132+
}
133+
124134
std::string preset = options.preset.empty() || options.preset == "realtime" ? "ultrafast" : options.preset;
125135
av_opt_set(codec_context->priv_data, "preset", preset.c_str(), 0);
126136
av_opt_set(codec_context->priv_data, "tune", "zerolatency", 0);
127-
av_opt_set(codec_context->priv_data, "profile", "baseline", 0);
128-
av_opt_set_int(codec_context->priv_data, "crf", 23, 0);
137+
av_opt_set_int(codec_context->priv_data, "crf", 20, 0);
138+
129139

130140
// CRITICAL: Configure for MP4 container - use AVCC format, not Annex B
131141
codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
132-
142+
133143
// Force AVCC format (length-prefixed NAL units) for MP4 compatibility
134144
av_opt_set_int(codec_context->priv_data, "annexb", 0, 0);
135-
145+
136146
// MOBILE COMPATIBILITY: Adaptive settings based on resolution
137-
DEBUG("Configuring H.264 for " + std::to_string(options.width) + "x" + std::to_string(options.height) +
138-
(isHighRes ? " (high resolution)" : isLowRes ? " (low resolution)" : " (standard resolution)"));
139-
147+
DEBUG("Configuring H.264 for " + std::to_string(options.width) + "x" + std::to_string(options.height) +
148+
(isFullHD ? " (high resolution)" : isLowRes ? " (low resolution)" : " (standard resolution)"));
149+
140150
// CRITICAL: Force keyframe generation and SPS/PPS inclusion
141151
av_opt_set_int(codec_context->priv_data, "force-cfr", 1, 0);
142-
143-
// MOBILE COMPATIBILITY: Adaptive keyframe interval based on resolution
144-
int keyframe_interval = isHighRes ? 60 : isLowRes ? 15 : 30;
152+
int keyframe_interval = isFullHD ? 90 : isHighRes ? 60 : isLowRes ? 15 : 30;
145153
av_opt_set_int(codec_context->priv_data, "keyint", keyframe_interval, 0);
146154
av_opt_set_int(codec_context->priv_data, "keyint_min", 1, 0);
147155
av_opt_set_int(codec_context->priv_data, "scenecut", 0, 0);
148156
av_opt_set_int(codec_context->priv_data, "intra-refresh", 0, 0);
149-
157+
150158
DEBUG("Using keyframe interval: " + std::to_string(keyframe_interval) + " frames for mobile compatibility");
151-
152-
// CRITICAL: Force full range encoding to match input
159+
153160
av_opt_set(codec_context->priv_data, "colorprim", "bt709", 0);
154161
av_opt_set(codec_context->priv_data, "transfer", "bt709", 0);
155162
av_opt_set(codec_context->priv_data, "colormatrix", "bt709", 0);
156163
av_opt_set(codec_context->priv_data, "range", "pc", 0); // Full range
157-
158-
// CRITICAL: Ensure SPS/PPS are written
164+
159165
av_opt_set_int(codec_context->priv_data, "repeat-headers", 1, 0); // Repeat SPS/PPS
160166
av_opt_set_int(codec_context->priv_data, "aud", 1, 0); // Add access unit delimiters
161-
162-
// MOBILE COMPATIBILITY: Optimize encoding settings for different resolutions
167+
163168
if (isLowRes) {
164-
// Low resolution: prioritize speed and compatibility
165-
av_opt_set(codec_context->priv_data, "level", "3.0", 0); // H.264 Level 3.0 for mobile
166-
av_opt_set_int(codec_context->priv_data, "refs", 1, 0); // Single reference frame
167-
av_opt_set_int(codec_context->priv_data, "b-frames", 0, 0); // No B-frames for simplicity
168-
} else if (isHighRes) {
169-
// High resolution: balance quality and compatibility
170-
av_opt_set(codec_context->priv_data, "level", "4.0", 0); // H.264 Level 4.0 for HD
171-
av_opt_set_int(codec_context->priv_data, "refs", 2, 0); // Two reference frames
172-
av_opt_set_int(codec_context->priv_data, "b-frames", 1, 0); // Minimal B-frames
169+
av_opt_set(codec_context->priv_data, "level", "3.0", 0);
170+
av_opt_set_int(codec_context->priv_data, "refs", 1, 0);
171+
av_opt_set_int(codec_context->priv_data, "b-frames", 0, 0);
172+
} else if (isFullHD) {
173+
av_opt_set(codec_context->priv_data, "level", "4.0", 0);
174+
av_opt_set_int(codec_context->priv_data, "refs", 2, 0);
175+
av_opt_set_int(codec_context->priv_data, "b-frames", 1, 0);
173176
} else {
174-
// Standard resolution: balanced settings
175-
av_opt_set(codec_context->priv_data, "level", "3.1", 0); // H.264 Level 3.1
176-
av_opt_set_int(codec_context->priv_data, "refs", 1, 0); // Single reference frame
177-
av_opt_set_int(codec_context->priv_data, "b-frames", 0, 0); // No B-frames
177+
av_opt_set(codec_context->priv_data, "level", "3.1", 0);
178+
av_opt_set_int(codec_context->priv_data, "refs", 1, 0);
179+
av_opt_set_int(codec_context->priv_data, "b-frames", 0, 0);
178180
}
179181

180-
// Use standard x264 options for MP4 compatibility
181182
av_opt_set(codec_context->priv_data, "x264opts", "force-cfr=1:no-scenecut=1", 0);
182183

183184
codec_context->thread_count = 1;
184185
codec_context->thread_type = FF_THREAD_FRAME;
185186

186187
codec_context->rc_buffer_size = options.bitrate;
187-
codec_context->rc_max_rate = static_cast<int>(options.bitrate * 1.2);
188-
codec_context->rc_min_rate = static_cast<int>(options.bitrate * 0.5);
188+
codec_context->rc_max_rate = static_cast<int>(options.bitrate * 1.5);
189+
codec_context->rc_min_rate = static_cast<int>(options.bitrate * 0.8);
189190

190191
av_opt_set_int(codec_context->priv_data, "fast-pskip", 1, 0);
191192
av_opt_set_int(codec_context->priv_data, "no-dct-decimate", 1, 0);
@@ -216,9 +217,9 @@ bool VideoRecorder::initialize_video()
216217
// VALIDATION: Verify SPS/PPS structure
217218
uint8_t* extradata = video_stream->codecpar->extradata;
218219
if (extradata[0] == 0x01) { // AVCC format marker
219-
DEBUG("AVCC format detected in extradata");
220+
DEBUG("AVCC format detected in extradata");
220221
} else {
221-
DEBUG("WARNING: Unexpected extradata format - may cause playback issues");
222+
DEBUG("⚠WARNING: Unexpected extradata format - may cause playback issues");
222223
}
223224
} else {
224225
ERROR("CRITICAL: No H.264 extradata found - SPS/PPS missing! Video will be unplayable.");
@@ -298,7 +299,6 @@ bool VideoRecorder::initialize_video()
298299
// Set MP4 specific options for proper MOOV atom handling
299300
AVDictionary *format_opts = nullptr;
300301

301-
// CRITICAL: Configure MP4 muxer for proper H.264 stream handling
302302
av_dict_set(&format_opts, "movflags", "faststart+frag_keyframe+empty_moov+default_base_moof", 0);
303303

304304
// Force proper H.264 stream format in MP4 container
@@ -332,7 +332,7 @@ bool VideoRecorder::initialize_video()
332332

333333
// VALIDATION: Verify MP4 container state after header write
334334
if (format_context->nb_streams != 1) {
335-
DEBUG("⚠️ WARNING: Expected 1 stream, got " + std::to_string(format_context->nb_streams));
335+
DEBUG("WARNING: Expected 1 stream, got " + std::to_string(format_context->nb_streams));
336336
}
337337

338338
if (video_stream->codecpar->codec_id != AV_CODEC_ID_H264) {
@@ -413,9 +413,9 @@ bool VideoRecorder::add_frame_rgba(const uint8_t* rgba_data, int width, int heig
413413

414414
bool needsScaling = (width != codec_context->width || height != codec_context->height);
415415
if (needsScaling) {
416-
std::cout << "[VideoRecorder] Automatic scaling enabled for adaptive dimensions" << std::endl;
416+
std::cout << "[VideoRecorder] Automatic scaling enabled for adaptive dimensions" << std::endl;
417417
} else {
418-
std::cout << "[VideoRecorder] Direct conversion - dimensions match" << std::endl;
418+
std::cout << "[VideoRecorder] Direct conversion - dimensions match" << std::endl;
419419
}
420420

421421
// Convert RGBA to YUV420P with scaling if needed

Lux/src/video_recorder.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ enum class RecordingState
3232

3333
struct RecordingOptions
3434
{
35-
int width = 512;
36-
int height = 512;
35+
int width = 1920;
36+
int height = 1080;
3737
int fps = 30;
38-
int bitrate = 2000000; // 2 Mbps
38+
int bitrate = 8000000; // 8 Mbps
3939
std::string codec = "libx264";
4040
std::string format = "mp4"; // Default to MP4 container
41-
std::string preset = "medium";
41+
std::string preset = "ultrafast";
4242
};
4343

4444
class VideoRecorder

0 commit comments

Comments
 (0)