Skip to content

Commit fad6752

Browse files
committed
Fix Android reverse rotation stream orientation
1 parent 9d9be51 commit fad6752

1 file changed

Lines changed: 94 additions & 27 deletions

File tree

server/src/android.rs

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,14 @@ pub struct AndroidFrame {
5858

5959
pub struct AndroidGrpcFrameStream {
6060
inner: tonic::Streaming<grpc::Image>,
61-
target_size: Option<(u32, u32)>,
61+
target: Option<AndroidFrameTarget>,
62+
}
63+
64+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
65+
struct AndroidFrameTarget {
66+
width: u32,
67+
height: u32,
68+
rotation_quarter_turns: u16,
6269
}
6370

6471
pub fn is_android_id(id: &str) -> bool {
@@ -517,21 +524,20 @@ impl AndroidBridge {
517524
display: 0,
518525
transport: None,
519526
};
520-
let target_size = self
527+
let target = self
521528
.resolve_serial(&avd_name)
522529
.ok()
523-
.and_then(|serial| self.screen_size_for_serial(&serial).ok())
524-
.map(|(width, height)| {
525-
(
526-
width.round().max(1.0) as u32,
527-
height.round().max(1.0) as u32,
528-
)
530+
.and_then(|serial| self.display_metrics_for_serial(&serial).ok())
531+
.map(|metrics| AndroidFrameTarget {
532+
width: metrics.width.round().max(1.0) as u32,
533+
height: metrics.height.round().max(1.0) as u32,
534+
rotation_quarter_turns: metrics.rotation_quarter_turns,
529535
});
530-
if let (Some(max_edge), Some((width, height))) = (max_edge, target_size) {
536+
if let (Some(max_edge), Some(target)) = (max_edge, target) {
531537
let max_edge = max_edge.clamp(240, 2400);
532-
let largest = width.max(height);
538+
let largest = target.width.max(target.height);
533539
if largest > max_edge {
534-
if width >= height {
540+
if target.width >= target.height {
535541
format.width = max_edge;
536542
} else {
537543
format.height = max_edge;
@@ -573,7 +579,7 @@ impl AndroidBridge {
573579
})?;
574580
Ok(AndroidGrpcFrameStream {
575581
inner: response.into_inner(),
576-
target_size,
582+
target,
577583
})
578584
}
579585

@@ -972,7 +978,7 @@ impl AndroidGrpcFrameStream {
972978
.unwrap_or(grpc::image_format::ImgFormat::Rgba8888),
973979
)?;
974980
let (width, height, rgba) =
975-
normalize_android_frame_orientation(width, height, rgba, self.target_size);
981+
normalize_android_frame_orientation(width, height, rgba, self.target);
976982
Ok(Some(AndroidFrame {
977983
width,
978984
height,
@@ -985,21 +991,28 @@ impl AndroidGrpcFrameStream {
985991
fn normalize_android_frame_orientation(
986992
width: u32,
987993
height: u32,
988-
rgba: Vec<u8>,
989-
target_size: Option<(u32, u32)>,
994+
mut rgba: Vec<u8>,
995+
target: Option<AndroidFrameTarget>,
990996
) -> (u32, u32, Vec<u8>) {
991-
let Some((target_width, target_height)) = target_size else {
997+
let Some(target) = target else {
992998
return (width, height, rgba);
993999
};
994-
if width == 0
995-
|| height == 0
996-
|| target_width == 0
997-
|| target_height == 0
998-
|| (width > height) == (target_width > target_height)
999-
{
1000+
if width == 0 || height == 0 || target.width == 0 || target.height == 0 {
10001001
return (width, height, rgba);
10011002
}
1002-
(height, width, rotate_rgba_clockwise(&rgba, width, height))
1003+
1004+
let (width, height) = if (width > height) == (target.width > target.height) {
1005+
(width, height)
1006+
} else {
1007+
rgba = rotate_rgba_clockwise(&rgba, width, height);
1008+
(height, width)
1009+
};
1010+
1011+
if target.rotation_quarter_turns >= 2 {
1012+
rotate_rgba_180_in_place(&mut rgba, width, height);
1013+
}
1014+
1015+
(width, height, rgba)
10031016
}
10041017

10051018
fn rotate_rgba_clockwise(rgba: &[u8], width: u32, height: u32) -> Vec<u8> {
@@ -1018,6 +1031,16 @@ fn rotate_rgba_clockwise(rgba: &[u8], width: u32, height: u32) -> Vec<u8> {
10181031
out
10191032
}
10201033

1034+
fn rotate_rgba_180_in_place(rgba: &mut [u8], width: u32, height: u32) {
1035+
let pixel_count = width as usize * height as usize;
1036+
for pixel in 0..(pixel_count / 2) {
1037+
let opposite = pixel_count - 1 - pixel;
1038+
for channel in 0..4 {
1039+
rgba.swap(pixel * 4 + channel, opposite * 4 + channel);
1040+
}
1041+
}
1042+
}
1043+
10211044
fn run_command_text<const N: usize>(program: PathBuf, args: [&str; N]) -> Result<String, AppError> {
10221045
let output = run_command(program, args)?;
10231046
String::from_utf8(output)
@@ -1685,8 +1708,16 @@ mod tests {
16851708
4, 0, 0, 255, 5, 0, 0, 255, 6, 0, 0, 255,
16861709
];
16871710

1688-
let (width, height, rotated) =
1689-
normalize_android_frame_orientation(3, 2, rgba, Some((2, 3)));
1711+
let (width, height, rotated) = normalize_android_frame_orientation(
1712+
3,
1713+
2,
1714+
rgba,
1715+
Some(AndroidFrameTarget {
1716+
width: 2,
1717+
height: 3,
1718+
rotation_quarter_turns: 0,
1719+
}),
1720+
);
16901721

16911722
assert_eq!((width, height), (2, 3));
16921723
assert_eq!(
@@ -1703,12 +1734,48 @@ mod tests {
17031734
fn android_frame_orientation_keeps_matching_aspect() {
17041735
let rgba = vec![1, 2, 3, 4, 5, 6, 7, 8];
17051736

1706-
let (width, height, out) =
1707-
normalize_android_frame_orientation(1, 2, rgba.clone(), Some((1080, 2400)));
1737+
let (width, height, out) = normalize_android_frame_orientation(
1738+
1,
1739+
2,
1740+
rgba.clone(),
1741+
Some(AndroidFrameTarget {
1742+
width: 1080,
1743+
height: 2400,
1744+
rotation_quarter_turns: 0,
1745+
}),
1746+
);
17081747

17091748
assert_eq!((width, height), (1, 2));
17101749
assert_eq!(out, rgba);
17111750
}
1751+
1752+
#[test]
1753+
fn android_frame_orientation_rotates_reverse_orientations_180() {
1754+
let rgba = vec![
1755+
1, 0, 0, 255, 2, 0, 0, 255, 3, 0, 0, 255, //
1756+
4, 0, 0, 255, 5, 0, 0, 255, 6, 0, 0, 255,
1757+
];
1758+
1759+
let (width, height, rotated) = normalize_android_frame_orientation(
1760+
3,
1761+
2,
1762+
rgba,
1763+
Some(AndroidFrameTarget {
1764+
width: 3,
1765+
height: 2,
1766+
rotation_quarter_turns: 3,
1767+
}),
1768+
);
1769+
1770+
assert_eq!((width, height), (3, 2));
1771+
assert_eq!(
1772+
rotated,
1773+
vec![
1774+
6, 0, 0, 255, 5, 0, 0, 255, 4, 0, 0, 255, //
1775+
3, 0, 0, 255, 2, 0, 0, 255, 1, 0, 0, 255,
1776+
]
1777+
);
1778+
}
17121779
}
17131780

17141781
mod grpc {

0 commit comments

Comments
 (0)