Skip to content

Video rotation metadata not propagated from mobile camera publish to watch renderer #933

@englishm-cloudflare

Description

@englishm-cloudflare

Summary

When publishing from a mobile device (e.g. iPhone camera via <hang-publish>), the video orientation is incorrect on the watch side. The phone captures in landscape natively (e.g. 640x480) even when held in portrait, but no rotation metadata is included in the catalog, and the watch-side renderer doesn't apply rotation even if it were present.

Steps to Reproduce

  1. Open a <hang-publish> page on an iPhone (using WebSocket fallback via @moq/web-transport-ws)
  2. Select camera source, hold phone in portrait orientation
  3. Open the corresponding <hang-watch> page in another browser
  4. Video appears rotated 90 degrees — the viewer sees the image sideways

Observed Behavior

  • Catalog contains 640x480 coded dimensions with no rotation field
  • The watch-side canvas renderer (watch/video/renderer.js) handles flip but not rotation
  • The publish side (publish/video/index.d.ts) exposes flip as a Signal but has no rotation Signal

Expected Behavior

  • The publish side should detect device orientation (e.g. via VideoFrame.rotation, window.screen.orientation, or MediaStreamTrack settings) and include rotation in the catalog
  • The watch-side renderer should read catalog.rotation and apply the appropriate transform when drawing frames to canvas

Analysis

The catalog schema already supports rotation (it appears in the type definitions for both publish and watch catalog types). The gap is:

  1. Publish: Video.Root has a flip: Signal<boolean> but no corresponding rotation signal, so rotation is never set in the catalog
  2. Watch: renderer.js lines 100-105 check catalog.flip and apply ctx.scale(-1, 1) but have no corresponding rotation logic

Environment

  • @moq/hang v0.1.2
  • @moq/web-transport-ws (WebSocket fallback)
  • Publishing from iPhone Safari (portrait), watching in Chrome desktop
  • Relay: cdn.moq.dev

Workaround

For now we're applying a CSS rotation on the watch side based on aspect ratio heuristics, but this is fragile and doesn't handle all cases correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions