Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,55 @@ public static List<MediaCodecInfo> getDecoderInfosSoftMatch(
.build();
}

/**
* Returns a list of decoders that can decode media in the specified format, in the priority order
* specified by the {@link MediaCodecSelector}.
* Unlike {@link #getDecoderInfosSoftMatch}, this method may exclude decoders that match the
* sample MIME type but do not support relevant format details.
*
* <p>This list is more complete than {@link #getDecoderInfos}, as it also considers alternative
* MIME types that are a close match using {@link #getAlternativeCodecMimeType}.
*
* @param context The application context.
* @param mediaCodecSelector The decoder selector.
* @param format The {@link Format} for which a decoder is required.
* @param requiresSecureDecoder Whether a secure decoder is required.
* @param requiresTunnelingDecoder Whether a tunneling decoder is required.
* @return A list of {@link MediaCodecInfo}s corresponding to decoders. May be empty.
* @throws DecoderQueryException Thrown if there was an error querying decoders.
*/
@RequiresNonNull("#3.sampleMimeType")
public static List<MediaCodecInfo> getDecoderInfosSoftMatchFilteredByFormatSupport(
Context context,
MediaCodecSelector mediaCodecSelector,
Format format,
boolean requiresSecureDecoder,
boolean requiresTunnelingDecoder)
throws DecoderQueryException {

List<MediaCodecInfo> decoderInfos =
mediaCodecSelector.getDecoderInfos(
format.sampleMimeType, requiresSecureDecoder, requiresTunnelingDecoder);

ImmutableList.Builder<MediaCodecInfo> result = ImmutableList.builder();

for (MediaCodecInfo decoderInfo : decoderInfos) {
if (!decoderInfo.isFormatSupported(context, format)) {
continue;
}
result.add(decoderInfo);
}

result.addAll(
getAlternativeDecoderInfos(
mediaCodecSelector,
format,
requiresSecureDecoder,
requiresTunnelingDecoder));

return result.build();
}

/**
* Returns a list of decoders for {@linkplain #getAlternativeCodecMimeType alternative MIME types}
* that can decode samples of the provided {@link Format}, in the priority order specified by the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3937,7 +3937,7 @@ public VideoTrackInfo(
== RendererCapabilities.HARDWARE_ACCELERATION_SUPPORTED;
this.resolvedMimeType = resolvedMimeType;
codecPreferenceScore = getVideoCodecPreferenceScore(resolvedMimeType);
isHdr = usesPrimaryDecoder && ColorInfo.isTransferHdr(format.colorInfo);
isHdr = usesPrimaryOrFallbackDecoder && ColorInfo.isTransferHdr(format.colorInfo);

@ybai001 ybai001 Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback decoder could be HDR too. For example,

  • Dolby Vision profile 8.1 content includes a HDR10 compatible HEVC base layer
  • Dolby Vision profile 8.4 content includes a HLG compatible HEVC base layer
  • Dolby Vision profile 10.1 content includes a HDR10 compatible AV1 base layer

If the target device is not Dolby Vision licensed, HEVC/HEVC/AV1 decoder will be primary decoder. And the corresponding base layer content is still HDR content.

selectionEligibility = evaluateSelectionEligibility(formatSupport, requiredAdaptiveSupport);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -940,8 +940,13 @@ private static List<MediaCodecInfo> getDecoderInfos(
return alternativeDecoderInfos;
}
}
return MediaCodecUtil.getDecoderInfosSoftMatch(
mediaCodecSelector, format, requiresSecureDecoder, requiresTunnelingDecoder);
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
return MediaCodecUtil.getDecoderInfosSoftMatchFilteredByFormatSupport(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We replace getDecoderInfosSoftMatch() with getDecoderInfosSoftMatchFilteredByFormatSupport() to resolve below two issues:

  1. Separate OMX Dolby Vision decoders per profile
    On some old Dolby Vision licensed devices (e.g. Philips 55OLED910/12), a dedicated OMX Dolby Vision decoder is for each DV profile (e.g. three decoders to support profile 5/8.x/9.x respectively). Assume the played content includes two tracks in manifest: one is DV P8.4, the other is SDR. If we're fortunate, the decoder supporting DV Profile 8.X appears first in the decoder list. In that case, it is treated as the preferred decoder, and Dolby Vision is played back on the device. But, if the first decoder in the list supports a different Dolby Vision profile (e.g. DV P5) than the one being played, it gets marked as isPreferred = false. So it receives a lower score in the Track Selector than an SDR decoder. This leads to incorrect track selection, where SDR is preferred over Dolby Vision even though the device fully supports the Dolby Vision profile being played.

  2. On the device, there is a single Dolby Vision decoder that supports both profile 5 and profile 8.x (HEVC based). The problem appears with Profile 10 (AV1 based). For example, consider a manifest containing P10.1 + SDR on a Dolby Vision-enabled device that supports P5, P8.x but not for P10.x. At the same time, this device also includes an AV1 decoder. With the current implementation, the SDR track will be selected. This happens because the Dolby Vision decoder is included in decoderInfos even though it does not support the requested Dolby Vision profile (P10.1), since the check is performed only against the MIME type. As a result, when such a decoder appears first in the list and is evaluated through isFormatSupported(), it reports that the format is not supported (i.e. it supports only p5 and p8.x). This triggers a decoder fallback to the AV1 decoder, but it also causes the decoder to be marked as isPreferred = false (which is wrong because the DV decoder shouldn't be on the list). For devices that do not support the requested Dolby Vision profile, the cross-compatible base layer decoder (AV1) should still be considered the preferred decoder - this is the same behavior that we can see on non Dolby Vision devices today.

context, mediaCodecSelector, format, requiresSecureDecoder, requiresTunnelingDecoder);
} else {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To minimize the risk, we just apply our new method MediaCodecUtil.getDecoderInfosSoftMatchFilteredByFormatSupport() to Dolby Vision only. In theory, we think this method should be applied to other formats too.

return MediaCodecUtil.getDecoderInfosSoftMatch(
mediaCodecSelector, format, requiresSecureDecoder, requiresTunnelingDecoder);
}
}

@RequiresApi(26)
Expand Down