Skip to content

[DASH] HDR10/HLG signalled via CICP EssentialProperty is not surfaced as HDR to DefaultTrackSelector #3426

Closed

Description

@akhilesh-dubey

Version

Media3 main branch

More version details

No response

Devices that reproduce the issue

Any device, this is a manifest‑parsing bug, not device‑specific. Verified on Samsung SM‑S908E (S22 Ultra) and Pixel 8 running Android 14.

Devices that do not reproduce the issue

N/A

Reproducible in the demo app?

Yes

Reproduction steps

  1. Use a DASH manifest containing an HEVC Main10 HDR10 Representation and an HEVC SDR Representation of the same or higher resolution.
    Signal HDR10 using the DASH CICP descriptors in the MPD, for example:
    <AdaptationSet ... contentType="video">
      <EssentialProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="9"></EssentialProperty>
      <EssentialProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="9"></EssentialProperty>
      <EssentialProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"></EssentialProperty>
      <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"></Role>
      <Representation sar="1:1" mimeType="video/mp4" codecs=.../>
      ...
  1. Start playback and observe which Representation is selected and its Format.colorInfo.

Expected result

The DASH parser should propagate the HDR information from the MPD into Format.colorInfo, allowing DefaultTrackSelector to identify the Representation as HDR during track selection.

When both HDR and SDR representations are otherwise comparable, the HDR representation should therefore be preferred on a device/display that supports HDR.

Actual result

DashManifestParser.buildFormat() does not populate Format.colorInfo for HDR10/HLG based on the CICP descriptors in the DASH MPD.

As a result, Format.colorInfo is null for the HDR10 Representation and DefaultTrackSelector.VideoTrackInfo.isHdr evaluates to false.

The HDR preference in DefaultTrackSelector therefore has no effect:

.compareFalseFirst(info1.isHdr, info2.isHdr)
.compare(info1.pixelCount, info2.pixelCount, qualityOrdering);

Track selection can consequently prefer the SDR Representation based on resolution/bitrate, even though an HDR10-capable Representation is available and the device supports HDR.

The actual HDR ColorInfo can be discovered later from the MP4 initialization segment by BoxParser.parseVideoSampleEntry through the colr box. However, this happens after the Representation has already been selected. The newly discovered color information therefore cannot influence the original track-selection decision.

Media

Root cause:
DashManifestParser.buildFormat() currently populates Format.colorInfo for Dolby Vision:

@Nullable ColorInfo colorInfo = null;
if (MimeTypes.isDolbyVisionCodec(codecs, supplementalCodecs)) {
  sampleMimeType = MimeTypes.VIDEO_DOLBY_VISION;
  colorInfo =
      Util.getColorInfoForDolbyVision(
          codecs, supplementalCodecs, supplementalProfiles);
  codecs = supplementalCodecs != null ? supplementalCodecs : codecs;
}

However, the DASH CICP descriptors used to signal HDR10/HLG are not currently mapped to Format.colorInfo.

The relevant descriptors are:

urn:mpeg:mpegB:cicp:MatrixCoefficients
urn:mpeg:mpegB:cicp:ColourPrimaries
urn:mpeg:mpegB:cicp:TransferCharacteristics

These descriptors are used by DASH specifications/profiles to signal color characteristics in the MPD.

Media3 already contains the required mapping helpers:

ColorInfo.isoColorPrimariesToColorSpace(int)
Util.isoTransferCharacteristicsToColorTransfer(int)

but these mappings are not currently used by DashManifestParser when constructing the Format.

Media: Any DASH manifest that follows DASH‑IF IOP §4.3 for HDR10 will reproduce.

Proposed fix

Parse the CICP descriptors from the DASH EssentialProperty and SupplementalProperty elements and populate Format.colorInfo during DashManifestParser.buildFormat().

For example:

private static final String CICP_SCHEME_PRIMARIES =
    "urn:mpeg:mpegB:cicp:ColourPrimaries";
private static final String CICP_SCHEME_TRANSFER =
    "urn:mpeg:mpegB:cicp:TransferCharacteristics";
private static final String CICP_SCHEME_MATRIX =
    "urn:mpeg:mpegB:cicp:MatrixCoefficients";

@Nullable
private static ColorInfo parseColorInfoFromMpdProperties(
    List<Descriptor> essentialProperties,
    List<Descriptor> supplementalProperties) {

  int isoTransfer = Format.NO_VALUE;
  int isoPrimaries = Format.NO_VALUE;
  boolean hasBt2020Matrix = false;

  for (Descriptor descriptor :
      Iterables.concat(essentialProperties, supplementalProperties)) {
    if (descriptor.value == null) {
      continue;
    }

    try {
      int value = Integer.parseInt(descriptor.value.trim());

      switch (descriptor.schemeIdUri) {
        case CICP_SCHEME_TRANSFER:
          isoTransfer = value;
          break;
        case CICP_SCHEME_PRIMARIES:
          isoPrimaries = value;
          break;
        case CICP_SCHEME_MATRIX:
          hasBt2020Matrix = value == 9;
          break;
      }
    } catch (NumberFormatException ignored) {
      // Ignore malformed values.
    }
  }

  @C.ColorTransfer
  int transfer =
      isoTransfer == Format.NO_VALUE
          ? Format.NO_VALUE
          : Util.isoTransferCharacteristicsToColorTransfer(isoTransfer);

  // Only expose HDR information here. Leave SDR unchanged so that
  // extraction can provide the exact values when available.
  if (transfer != C.COLOR_TRANSFER_ST2084
      && transfer != C.COLOR_TRANSFER_HLG) {
    return null;
  }

  @C.ColorSpace
  int colorSpace =
      isoPrimaries == Format.NO_VALUE
          ? (hasBt2020Matrix ? C.COLOR_SPACE_BT2020 : Format.NO_VALUE)
          : ColorInfo.isoColorPrimariesToColorSpace(isoPrimaries);

  return new ColorInfo.Builder()
      .setColorSpace(colorSpace)
      .setColorTransfer(transfer)
      .build();
}

Then, after the existing Dolby Vision handling:

if (colorInfo == null && MimeTypes.isVideo(sampleMimeType)) {
  colorInfo =
      parseColorInfoFromMpdProperties(
          essentialProperties, supplementalProperties);
}

This would allow HDR10/HLG information available in the DASH MPD to participate in track selection, while preserving the existing extraction path for more detailed color information.

Bug Report

Activity

  1. self-assigned this
    on Sep 22, 2026
  2. microkatz commented on Sep 22, 2026

    @microkatz
    Contributor

    @akhilesh-dubey

    Thanks for the detailed report and analysis!

    We've prepared a fix to parse the DASH CICP descriptors (ColourPrimaries, TransferCharacteristics, MatrixCoefficients, and VideoFullRangeFlag) from EssentialProperty and SupplementalProperty elements into Format.colorInfo in DashManifestParser, so that HDR10 and HLG representations are properly surfaced to DefaultTrackSelector during track selection.

    We're working on getting the fix reviewed and submitted to main shortly—this issue will be updated automatically once the commit lands.

  3. akhilesh-dubey commented on Sep 23, 2026

    @akhilesh-dubey
    Author

    Thanks for the update, appreciate it!

  4. microkatz commented on Oct 1, 2026

    @microkatz
    Contributor

    Hello @akhilesh-dubey,

    I have submitted a fix, ebccde8, into the main branch that will ensure parsing of the CICP properties.

    Hopefully this addresses your issue and so I will close this ticket. If it does not then feel free to re-open or create a new ticket!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions