Convert HDR 10-bit to SDR 8-bit for HLS delivery on Apple devices

With Wowza Streaming Engine 4.9.7, we added support for converting 10-bit HDR sources (H.265/HEVC Main10, Rec.2020, PQ/HLG) to 8-bit SDR outputs (H.264/AVC or H.265/HEVC Main, Rec.709, gamma) for HLS delivery on Apple devices.

The workflow includes full-color-space conversion — translating HDR transfer functions, primaries, and Y′CbCr matrices into their SDR equivalents — alongside tone mapping and gamut mapping. This ensures SDR fallback streams comply with Apple’s HLS authoring requirements, preserving visual fidelity while maintaining compatibility across both HDR-capable and legacy SDR devices.

Wowza Streaming Engine can ingest 10-bit HDR10 video encoded with H.265/HEVC and transcode it to 10-bit H.265/HEVC without HDR metadata (SDR). By default, when EVA-based NVIDIA acceleration is enabled, and the source is 10-bit, the transcoder produces 10-bit outputs for the selected ABR ladder.

This article explains how to override that behavior and convert HDR 10-bit H.265/HEVC inputs into 8-bit SDR outputs through bit-depth reduction and color-space transformation.

Note: 10-to-8-bit color-depth conversion is available only when using the EVA-based NVIDIA GPU transcoding pipeline.

Before you start


For the purposes of this tutorial, please be aware of the following:

  • We use the default live application included with Wowza Streaming Engine.
  • You must ingest a 10-bit HDR source to complete this workflow. For testing, you can use the HDR 10-bit H.265/HEVC Exodus sample found in these 4K (UltraHD) & HDR Format videos.

1. Configure your live application


First, configure your Wowza Streaming Engine live application by enabling the Transcoder and adding .stream files to enable publishing and playing your live stream over UDP.

  1. Go to the live application in Wowza Streaming Engine.
  2. Go to the Source Security page, click Edit.
  3. For testing purposes, set all RTMP Sources and RTSP Sources to Open (no authentication required).
  4. Restart the application for changes to take effect.
  5. Go to the Setup tab for your application, select either the Apple HLS playback type or the CMAF packetizer.
Note: Some playback environments—such as Safari on iOS and macOS—require H.265/HEVC to be delivered in CMAF-compatible fragmented MP4 segments, because  Apple's native media stack doesn't support HEVC in MPEG-TS. For these situations, CMAF is the required packetizer.
  1. Enable the Wowza Streaming Engine Transcoder. For more, see the Enable the Transcoder section.
  2. Restart the application for changes to take effect.
  3. Go to the Stream Files page and click Add Stream File.
  4. Add a stream file with the following values, then click Add to save. For more, see Create and use .stream files in Wowza Streaming Engine or Publish and play a live stream from an MPEG-TS encoder in Wowza Streaming Engine.
  • Name for the new stream file: myStream.stream
  • Stream URI: udp://0.0.0.0:[port]
  1. Return to the Stream Files page.
  2. To start the stream, click the Connect icon.
  3. In the Connect a Stream File modal, connect to the default application instance, select rtp from the MediaCaster Type dropdown, and click OK.

2. Configure your transcoding templates


Next, configure your Transcoder templates to convert HDR 10-bit H.265/HEVC input into 8-bit SDR output. The live application type includes an example Wowza Streaming Engine Transcoder template with pre-configured parameters to simplify the 10-bit-to-8-bit conversion process.

Toggle between the Single bitrate output and Multiple bitrate output tabs depending on your use case.

Single bitrate output

  1. Go to the Transcoder page for your live application.
  2. Change the Fallback Template to Transcode H.265 with Bit Depth Conversion (Default). This default template is pre-configured with the encoding presets in the following table.
Note: The Transcode H.265 with Bit Depth Conversion (Default) template is included with new installations of Wowza Streaming Engine 4.9.7 and later. When upgrading from an earlier version, this template is not added automatically and will not be available unless it's manually configured. Download the transcode-h265HDRtoSDR.zip.

Encoding preset Description
source Passes the source video stream through to an output rendition without making any changes.
1080p Transcodes the video to H.265 and outputs a 1080p rendition using the NVENC EVA encoding implementation.
1080p 8-bit-color Transcodes the video to H.265 and outputs a 1080p rendition using the NVENC EVA encoding implementation. The Convert to 8-bit setting is enabled to force the conversion to the 8-bit color depth.
720p Transcodes the video to H.265 and outputs a 720p rendition using the NVENC EVA encoding implementation.
720p 8-bit-color Transcodes the video to H.265 and outputs a 720p rendition using the NVENC EVA encoding implementation. The Convert to 8-bit setting is enabled to force the conversion to the 8-bit color depth.
Note: Each preset is also set to automatically use the NVCUVID EVA decoding and CUDA EVA scaling implementations.
  1. Restart the application for changes to take effect.
  2. On the Transcoder page, in the Transcoder Templates section, click the Transcode H.265 with Bit Depth Conversion (Default) template.
  3. For a single output, modify the encoding presets. For example, when outputting a 1080p rendition that's also converted to 8-bit color, enable only the 1080p 8-bit-color preset and disable all other presets.
Note: To deactivate presets, click each preset name, then click Disable Preset.
  1. This setup creates the following single rendition (in addition to the source stream) when publishing your live stream to Wowza Streaming Engine;

Multiple bitrate output

  1. Go to the Transcoder page for your live application.
  2. Change the Fallback Template to Transcode H.265 with Bit Depth Conversion (Default). This default template is pre-configured with the encoding presets in the following table.
Note: The Transcode H.265 with Bit Depth Conversion (Default) template is included with new installations of Wowza Streaming Engine 4.9.7 and later. When upgrading from an earlier version, this template is not added automatically and will not be available unless it's manually configured. Download the transcode-h265HDRtoSDR.zip.
Encoding preset Description
source Passes the source video stream through to an output rendition without making any changes.
1080p Transcodes the video to H.265 and outputs a 1080p rendition using the NVENC EVA encoding implementation.
1080p 8-bit-color Transcodes the video to H.265 and outputs a 1080p rendition using the NVENC EVA encoding implementation. The Convert to 8-bit setting is enabled to force the conversion to the 8-bit color depth.
720p Transcodes the video to H.265 and outputs a 720p rendition using the NVENC EVA encoding implementation.
720p 8-bit-color Transcodes the video to H.265 and outputs a 720p rendition using the NVENC EVA encoding implementation. The Convert to 8-bit setting is enabled to force the conversion to the 8-bit color depth.
Note: Each preset is also set to automatically use the NVCUVID EVA decoding and CUDA EVA scaling implementations.
  1. Restart the application for changes to take effect.
  2. On the Transcoder page, in the Transcoder Templates section, click the Transcode H.265 with Bit Depth Conversion (Default) template.
  3. For workflows with multiple output renditions, adjust the encoding presets accordingly. For example, if you need both 10-bit and 8-bit variants of a 1080p output, enable the 1080p 8-bit-color preset and the standard 1080p preset, and disable all other presets. Because these two outputs share the same resolution, you must use one of the following SMIL files to distinguish between the outputs during playback:

For HLS Cupertino-packetized stream (MPEG-TS)

<?xml version="1.0" encoding="UTF-8"?>
<smil title="SMIL file for live streaming">
  <body>
    <switch>
      <video src="myStream.stream_1080p" title="1080p Stream">
        <param name="videoBitrate" value="3000000" valuetype="data"></param>
        <param name="audioBitrate" value="96000" valuetype="data"></param>
      </video>
      <video src="myStream.stream_1080p_8-bit_color" title="1080p 8-bit Stream">
        <param name="videoBitrate" value="3000001" valuetype="data"></param>
        <param name="audioBitrate" value="96000" valuetype="data"></param>
      </video>
    </switch>
  </body>
</smil>

For HLS CMAF-packetized stream (fMP4) 

<?xml version="1.0" encoding="UTF-8"?>
<smil title="SMIL file for live streaming">
  <body>
    <switch>
      <video src="myStream.stream_1080p" title="1080p Stream">
        <param name="videoBitrate" value="30000000" valuetype="data"></param>
        <param name="videoOnly" value="TRUE" valuetype="data"/>
        <param name="cupertinoTag.AUDIO" value="audio" valuetype="data"/>
      </video>
      <video src="myStream.stream_1080p_8-bit_color" title="1080p 8-bit Stream">
        <param name="videoBitrate" value="30000001" valuetype="data"></param>
        <param name="videoOnly" value="TRUE" valuetype="data"/>
        <param name="cupertinoTag.AUDIO" value="audio" valuetype="data"/>
      </video>
      <audio src="myStream.stream" system-language="en" audio-bitrate="105768">
        <param name="cupertinoTag" value="EXT-X-MEDIA" valuetype="data"/>
        <param name="cupertinoTag.GROUP-ID" value="audio" valuetype="data"/>
      </audio>
    </switch>
  </body>
</smil>
Notes: 
  • Stream Name Groups can be used instead of a SMIL file, but only for HLS outputs generated with the Cupertino packetizer. CMAF-packetized HLS streams require a SMIL file.
  • When using a SMIL file to define both 10-bit and 8-bit variants at the same resolution, you must specify a unique title attribute for each <video> element to ensure the renditions are correctly differentiated. Optionally, you can also increment the videoBitrate value (for example, by 1) to further distinguish the variants, though this is not required.
  • For more, see Create and configure a SMIL file.
  1. This setup creates the following multiple renditions when publishing your live stream to Wowza Streaming Engine:

3. Publish your stream


Next, use the steps in this section to start your HDR live stream and to send it to your Wowza Streaming Engine server.

  1. From the directory containing your video asset, use the following ffmpeg command to publish your stream to Wowza Streaming Engine. For more about publishing live streams, see Connect a live source to Wowza Streaming Engine.
ffmpeg \
  -stream_loop -1 \
  -re \
  -i hevc_hdr_exodus.mp4 \
  -c:v copy \
  -c:a aac \
  -f mpegts \
  "udp://localhost:10000?pkt_size=1316"
Note: H.265/HEVC cannot be delivered over RTMP, because RTMP only supports H.264 video. To send H.265, you must use an MPEG-TS transport stream, which is typically delivered over UDP. As a result, UDP is required for this workflow.
  1. The ffmpeg console output confirms the H.265/HEVC codec and yuv420p10le pixel format for HDR-capable 10-bit video:
Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568),
yuv420p10le(tv, bt2020nc/bt2020/smpte2084, progressive),
1920x1080 [SAR 1:1 DAR 16:9],
q=2-31,
5474 kb/s,
24 fps, 24 tbr, 90k tbn (default)
Note: For 8-bit SDR outputs, the expected and most widely supported pixel format is yuv420p. This format is required for broad compatibility with HLS playback on Apple devices and is the default for H.265/AVC and 8-bit HEVC/H.265 streams.
  1. In Wowza Streaming Engine, go to the Incoming Streams page for the application and verify that the stream appears as active.

4. Test playback


With the setup in this article, the HLS master playlist advertises multiple variants. When Safari loads the master playlist, it checks codec support, bit-depth support, color-space support (Rec.2020 vs Rec.709), required container format (HEVC must be fMP4/CMAF), and hardware-decoding support. If the device can decode 10-bit HDR H.265/HEVC, it may choose that rendition. If it cannot, or if conditions aren't ideal, it falls back to the 8-bit SDR variant.

Examples of triggers:

  • The device does not support HDR → falls back to SDR.
  • The device is older and does not support HEVC → falls back to H.264.
  • The rendition is in MPEG-TS with HEVC (not supported) → fallback.
  • The device supports HEVC but not 10-bit → fallback to 8-bit HEVC or H.264.

This happens automatically. You can use the following URLs to test playback on Apple devices:

Use case Playback URL
For the source stream https://[server-ip-address]/live/_definst_/myStream.stream/playlist.m3u8
For single bitrate output (without a SMIL file)

https://[server-ip-address]/live/_definst_/myStream.stream_1080p_8-bit_color/playlist.m3u8

For multiple bitrate outputs, HLS-packetized (with a SMIL file) https://[server-ip-address]/live/_definst_/smil:myStream.smil/playlist.m3u8
For multiple bitrate outputs, CMAF-packetized (with a SMIL file) https://[server-ip-address]/live/_definst_/smil:myStream.smil/playlist_sfm4s.m3u8

More resources