#18487·mpv

Add --sub-sdr-peak for independent SDR subtitle luminance

Author: carycary246Created Sep 15, 2026Updated Sep 15, 2026
Labelsmeta:feature-request

Expected behavior of the wanted feature

Background --sub-hdr-peak provides a useful way to control subtitle luminance without changing the subtitle's nominal RGB/color values. For example: sub-hdr-peak=100allows white subtitle text to be rendered at a lower diffuse-white luminance while remaining nominally white, rather than requiring sub-color to change the RGB value.

However, with --sub-hdr-peak recent commits changed this to an HDR-output option. With the current vo=gpu-next implementation, it is only applied when the source video has an HDR transfer function.

This leaves no equivalent control for SDR subtitles when rendering SDR video.

Requested feature add --sub-sdr-peak=<auto|sdr|10-10000> to control the diffuse-white luminance of text subtitles and OSD when their subtitle colorspace is SDR.

The semantics could mirror --sub-hdr-peak:

  • auto (default): preserve the current behavior.
  • sdr: use the standard SDR reference white (203 cd/m²).
  • A numeric value: use that value in cd/m² as the subtitle diffuse-white level.

For example: sub-sdr-peak=100 would cause nominally white subtitle text (RGB 1.0, 1.0, 1.0) to be rendered at 100 nits, rather than changing the subtitle RGB to something like #b0b0b0.

This is useful for users who want to reduce subtitle brightness while preserving subtitle colors and ASS styling.

Why not use sub-color? sub-color changes the actual RGB value of the subtitle. sub-color=#aaaaaa is not equivalent to assigning a lower luminance to white subtitle RGB. In particular, changing the RGB value can affect colored subtitles, ASS styles, and the intended relationship between subtitle colors.

--sub-sdr-peak would instead control the color-space/luminance interpretation of the subtitle, analogous to the existing HDR option.

Proposed implementation The existing libass_overlay_color() already constructs a pl_color_space for the subtitle and uses color.hdr.max_luma to specify the diffuse-white level. Therefore this should not require any changes to subtitle rendering itself.

The existing:

if (src && pl_color_transfer_is_hdr(src->params.color.transfer) &&
    p->next_opts->sub_hdr_peak)
{
    color.hdr = (struct pl_hdr_metadata) {
        .max_luma = p->next_opts->sub_hdr_peak,
    };
} else if (ref_luma && !pl_color_transfer_is_hdr(color.transfer)) {
    color.hdr.max_luma = ref_luma;
}
`
could become `if (src && pl_color_transfer_is_hdr(src->params.color.transfer) &&
    p->next_opts->sub_hdr_peak)
{
    color.hdr = (struct pl_hdr_metadata) {
        .max_luma = p->next_opts->sub_hdr_peak,
    };
} else if (!pl_color_transfer_is_hdr(color.transfer) &&
           p->next_opts->sub_sdr_peak)
{
    color.hdr.max_luma = p->next_opts->sub_sdr_peak;
} else if (ref_luma && !pl_color_transfer_is_hdr(color.transfer)) {
    color.hdr.max_luma = ref_luma;
}

could become:

if (src && pl_color_transfer_is_hdr(src->params.color.transfer) &&
    p->next_opts->sub_hdr_peak)
{
    color.hdr = (struct pl_hdr_metadata) {
        .max_luma = p->next_opts->sub_hdr_peak,
    };
} else if (!pl_color_transfer_is_hdr(color.transfer) &&
           p->next_opts->sub_sdr_peak)
{
    color.hdr.max_luma = p->next_opts->sub_sdr_peak;
} else if (ref_luma && !pl_color_transfer_is_hdr(color.transfer)) {
    color.hdr.max_luma = ref_luma;
}

and gl_next_opts would gain:

int sub_sdr_peak;

with an option definition mirroring sub-hdr-peak:

{"sub-sdr-peak", OPT_CHOICE(sub_sdr_peak,
    {"auto", 0},
    {"sdr", PL_COLOR_SDR_WHITE}),
    M_RANGE(10, 10000)},

No explicit default would be necessary beyond zero/auto, preserving existing behavior.

The resulting option definitions would therefore be symmetrical:

--sub-sdr-peak   diffuse white for SDR subtitle rendering
--sub-hdr-peak   diffuse white for HDR subtitle rendering

Interaction with sub-hdr-peak The two options should be mutually exclusive based on the subtitle colorspace:

HDR subtitle colorspace → sub-hdr-peak

SDR subtitle colorspace → sub-sdr-peak

Thus an HDR video with normal SDR subtitles would continue to use the existing HDR subtitle handling, while an SDR subtitle rendered in an SDR colorspace could use sub-sdr-peak.

The default auto behavior would remain unchanged, so existing configurations would not be affected.

Alternative behavior of the wanted feature

No response

Log File

No response

Sample Files

No response