Skip to content

Commit 243541e

Browse files
fix(nodes): pass display resolution to VA-API encoders (fixes #292)
The AV1 encoder was passing only the superblock-aligned coded resolution to cros-codecs, which set render_width/render_height in the AV1 frame header to the coded dimensions. For non-aligned inputs (e.g. 1280×720 → coded 1280×768), decoders would show 48 pixels of black padding at the bottom. Add a display_resolution field to the vendored cros-codecs AV1 EncoderConfig and use it for render_width/render_height in the frame header predictor. When display differs from coded dimensions, the AV1 bitstream now signals render_and_frame_size_different=1 so decoders crop the superblock padding. For H.264, the SpsBuilder::resolution() method already handles macroblock alignment and frame_crop offsets automatically, but we were passing the pre-aligned coded resolution, bypassing the cropping logic. Now we pass the original display resolution and let SpsBuilder compute the correct frame_crop offsets. Closes #292 Signed-off-by: StreamKit Devin <devin@streamkit.dev> Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
1 parent a469a46 commit 243541e

File tree

4 files changed

+29
-3
lines changed

4 files changed

+29
-3
lines changed

crates/nodes/src/video/vaapi_av1.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,10 +973,20 @@ impl StandardVideoEncoder for VaapiAv1Encoder {
973973
}
974974
};
975975

976+
// Pass display_resolution so the AV1 frame header sets
977+
// render_width/render_height to the visible area, not the
978+
// superblock-aligned coded dimensions (fixes #292).
979+
let display_res = if width != coded_width || height != coded_height {
980+
Some(CrosResolution { width, height })
981+
} else {
982+
None
983+
};
984+
976985
let cros_config = CrosEncoderConfig {
977986
profile: Av1Profile::Profile0,
978987
bit_depth: cros_codecs::codec::av1::parser::BitDepth::Depth8,
979988
resolution: CrosResolution { width: coded_width, height: coded_height },
989+
display_resolution: display_res,
980990
pred_structure: PredictionStructure::LowDelay { limit: 1024 },
981991
initial_tunings: Tunings {
982992
rate_control: RateControl::ConstantQuality(config.quality),

crates/nodes/src/video/vaapi_h264.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,11 @@ impl StandardVideoEncoder for VaapiH264Encoder {
737737
}
738738
};
739739

740+
// Pass the display resolution (not the macroblock-aligned coded
741+
// resolution) so SpsBuilder::resolution() computes frame_crop offsets
742+
// automatically, preventing visible padding bars (fixes #292).
740743
let cros_config = CrosH264EncoderConfig {
741-
resolution: CrosResolution { width: coded_width, height: coded_height },
744+
resolution: CrosResolution { width, height },
742745
profile: H264Profile::Main,
743746
level: H264Level::L4,
744747
pred_structure: PredictionStructure::LowDelay { limit: 1024 },

vendor/cros-codecs/src/encoder/av1.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ pub struct EncoderConfig {
1515
pub profile: Profile,
1616
pub bit_depth: BitDepth,
1717
pub resolution: Resolution,
18+
/// Display resolution (visible area) when it differs from coded resolution.
19+
/// Used to set `render_width`/`render_height` in the AV1 frame header so
20+
/// decoders crop superblock-alignment padding instead of showing black bars.
21+
pub display_resolution: Option<Resolution>,
1822
pub pred_structure: PredictionStructure,
1923
/// Initial tunings values
2024
pub initial_tunings: Tunings,
@@ -27,6 +31,7 @@ impl Default for EncoderConfig {
2731
profile: Profile::Profile0,
2832
bit_depth: BitDepth::Depth8,
2933
resolution: Resolution { width: 320, height: 240 },
34+
display_resolution: None,
3035
pred_structure: PredictionStructure::LowDelay { limit: 1024 },
3136
initial_tunings: Default::default(),
3237
}

vendor/cros-codecs/src/encoder/stateless/av1/predictor.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ impl<Picture, Reference> LowDelayAV1<Picture, Reference> {
136136
let width = self.delegate.config.resolution.width;
137137
let height = self.delegate.config.resolution.height;
138138

139+
// Use display resolution for render_width/render_height when the
140+
// visible area is smaller than the coded frame (superblock alignment
141+
// padding). This sets render_and_frame_size_different=1 in the frame
142+
// header so decoders crop the padding instead of showing black bars.
143+
let display = self.delegate.config.display_resolution.as_ref();
144+
let render_width = display.map_or(width, |r| r.width);
145+
let render_height = display.map_or(height, |r| r.height);
146+
139147
// Superblock size
140148
let sb_size = if self.delegate.sequence.use_128x128_superblock { 128 } else { 64 };
141149

@@ -213,8 +221,8 @@ impl<Picture, Reference> LowDelayAV1<Picture, Reference> {
213221
upscaled_width: width,
214222
frame_width: width,
215223
frame_height: height,
216-
render_width: width,
217-
render_height: height,
224+
render_width,
225+
render_height,
218226

219227
..Default::default()
220228
})

0 commit comments

Comments
 (0)