Repository navigation
Conversation
ReplayKit delivers the screen as a portrait buffer and carries the device orientation only in RPVideoSampleOrientationKey. Since e0d899d the pipeline swaps the encoder footprint on rotation, but the pixel transfer only letterboxed the portrait buffer into it, so landscape streamed a narrow portrait strip with the UI sideways. Rotate the frame before encoding. iOS has no rotating pixel transfer and a VTPixelRotationSession cannot scale, so a rotated frame is scaled into an encoder-sized buffer in the un-rotated orientation and then rotated into the encoder buffer. Upright frames keep the existing path, and the direct-source shortcut is skipped while a rotation is needed. Rotation needs iOS 16; iOS 15 keeps the previous behaviour. The quarter-turn mapping was measured on an iPhone 15 Pro (iOS 26.6.1): it reads upright opposite to the CGImagePropertyOrientation docs. Refs DRO-3359 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
niko-droidrun
approved these changes
Oct 14, 2026
Timo972
deleted the
timo/dro-3359-ios-wda-stream-landscape-picture-stays-un-rotated-portrait
branch
October 14, 2026 11:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes DRO-3359.
Problem
On WDA-controlled phones (iOS < 27), rotating to landscape flips the stream to 1278×588, so the viewer rotates its frame. The picture inside stays un-rotated: a narrow portrait strip with the UI drawn sideways, in Chrome and Safari.
ReplayKit always hands the broadcast extension a portrait buffer and carries the orientation only in
RPVideoSampleOrientationKey. Since #33 (e0d899d1), the pipeline swaps the encoder size on rotation, butVTPixelTransferSessionTransferImageonly letterboxes the portrait buffer into the new landscape size and never rotates it.Change
FBBroadcastFrameRotationmaps the orientation tag to the turn that makes the buffer upright: 3 → 180°, 6 → 90° counter-clockwise, 8 → 90° clockwise. Unknown and mirrored values (which ReplayKit doesn't emit) map to no rotation.FBExtSessionPipelinehandles rotated frames in two steps, because iOS has no rotating pixel transfer (kVTPixelTransferPropertyKey_Rotationis macOS-only) andVTPixelRotationSessioncan't scale:The quarter-turn mapping is the opposite of what the
CGImagePropertyOrientationdocs suggest. I first implemented it per the docs, and both landscape directions came out upside down on hardware; the code comment records the measured mapping.Verification
UnitTests255 passed, 1 skipped, including two new tests forFBBroadcastFrameRotation.Scripts/ci/build-real.shdoes, then signed and installed it withmobilerun-ios setup --reinstall. A probe brought the broadcast up (stateconnected), opened the portal's H.265 capture (50%, 60 fps) with Safari in front, and stepped portrait → landscapeLeft → portrait → landscapeRight → portrait through CoreDevicechangeOrientation. For each step I decoded a frame with ffmpeg:🤖 Generated with Claude Code