Portrait video gets a full-HD upgrade on Cloudflare Stream

Cloudflare Stream now processes newly uploaded portrait videos in full HD quality, closing a gap that left vertical video looking soft and grainy on the smartphones where it is most often viewed. The change replaces the old pipeline behavior, which encoded portrait video using landscape-oriented constraints and produced noticeably lower-resolution output.

Previously, portrait HD video was scaled using the same height-constrained renditions as landscape video. Because those renditions are defined by target height, a portrait video that should have been 1080x1920 was instead encoded at 1080x606. Modern phone displays are all HD, so the quality loss was obvious whenever vertical video was viewed in portrait mode.

Under the new system, portrait videos are encoded with a constrained target width, using a mirrored set of standard resolutions: 240x426 up to 1080x1920. VOD encoding and on-the-fly encoding (OTFE) both apply the new logic, so the improvement covers uploads and live ingest alike.

How the encoding pipeline changed

Cloudflare Stream encodes each uploaded video into multiple renditions so playback can adapt to the viewer's network. A viewer on a slow mobile connection might receive a 240p stream (320x240), while someone on fiber gets the 1080p rendition (1920x1080). The pipeline had two paths: the video on-demand (VOD) encoder, which pre-generates and stores segments at each resolution, and the on-the-fly encoder, which generates renditions on request using the same process as Stream Live.

Both paths identified renditions by their output height. That meant the pipeline was effectively orientation-agnostic, and orientation-specific logic had to be threaded through several stages:

  • Stream API service: This service enqueues rendition encoding jobs after upload. It now selects from a new set of portrait renditions when the source video is vertical.
  • OTFE delivery: The delivery layer, which runs on Cloudflare Workers, now generates portrait-specific encoding resolutions and passes them to the on-the-fly encoder.
  • Player quality labels: The built-in Stream player previously displayed quality levels by height. For portrait video, it now shows the constraining dimension, which for old-pipeline portrait video is a more honest label. A 9:16 video encoded under the old system at 608x1080 is now correctly marked 608p rather than appearing as 1080p.

Encoding jobs themselves flow through Cloudflare's in-house queue management system, which handles jobs generically, so no changes were needed there. The broader Stream service leverages Cloudflare's own Developer Platform products — Workers for delivery, R2 for rendition storage, Workers AI for captioning, and Durable Objects for bitrate observation.

Measured quality improvement

The pipeline change was validated using the peak-signal-to-noise ratio (PSNR), a standard mathematical measure of image quality. The comparison pits an upscaled version of the old pipeline's output against the new pipeline's rendition, both relative to the unencoded source.

Quality gains reached as high as 8% by PSNR. The visible difference is often greater than that number suggests, especially in footage with fine detail or motion. Sample comparisons show clear improvements in text sharpness and in fine features like hair and makeup detail.

Testing also surfaced a handful of edge cases:

  • A bug in OTFE logic caused some new portrait livestream renditions to have negative bitrates, making them unusable. The root cause was an internal representation of constraining dimensions being mistakenly used for bitrate observation. End-to-end test coverage was expanded to include more portrait video and live recording scenarios.
  • Downloading very small videos sometimes failed. For videos under 240p, the smallest encoding resolution, the non-constraining dimension was not scaled to preserve aspect ratio, causing some videos to be misclassified as portrait or landscape. The fix required specific dimension combinations to reproduce, and additional unit tests for small videos were added after the fix.

Portrait HD encoding is available now for new uploads to Cloudflare Stream. Developers can verify the change by uploading a vertical video and comparing the available quality levels in the player's gear menu.