Search in sources :

Example 1 with DecoderQueryException

use of androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException in project media by androidx.

the class EnumerateDecodersTest method logDecoderInfos.

private void logDecoderInfos(String mimeType, boolean secure, boolean tunneling) throws DecoderQueryException {
    List<MediaCodecInfo> mediaCodecInfos = MediaCodecUtil.getDecoderInfos(mimeType, secure, tunneling);
    for (MediaCodecInfo mediaCodecInfo : mediaCodecInfos) {
        CodecCapabilities capabilities = mediaCodecInfo.capabilities;
        metricsLogger.logMetric("capabilities_" + mediaCodecInfo.name, codecCapabilitiesToString(mimeType, capabilities));
    }
}
Also used : MediaCodecInfo(androidx.media3.exoplayer.mediacodec.MediaCodecInfo) CodecCapabilities(android.media.MediaCodecInfo.CodecCapabilities)

Example 2 with DecoderQueryException

use of androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException in project media by androidx.

the class MediaCodecAudioRenderer method supportsFormat.

@Override
@Capabilities
protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format) throws DecoderQueryException {
    if (!MimeTypes.isAudio(format.sampleMimeType)) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
    }
    @TunnelingSupport int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
    boolean formatHasDrm = format.cryptoType != C.CRYPTO_TYPE_NONE;
    boolean supportsFormatDrm = supportsFormatDrm(format);
    // Else we don't don't need a decoder at all.
    if (supportsFormatDrm && audioSink.supportsFormat(format) && (!formatHasDrm || MediaCodecUtil.getDecryptOnlyDecoderInfo() != null)) {
        return RendererCapabilities.create(C.FORMAT_HANDLED, ADAPTIVE_NOT_SEAMLESS, tunnelingSupport);
    }
    // the input format directly.
    if (MimeTypes.AUDIO_RAW.equals(format.sampleMimeType) && !audioSink.supportsFormat(format)) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
    }
    // For all other input formats, we expect the decoder to output 16-bit PCM.
    if (!audioSink.supportsFormat(Util.getPcmFormat(C.ENCODING_PCM_16BIT, format.channelCount, format.sampleRate))) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
    }
    List<MediaCodecInfo> decoderInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */
    false, audioSink);
    if (decoderInfos.isEmpty()) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
    }
    if (!supportsFormatDrm) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_DRM);
    }
    // Check whether the first decoder supports the format. This is the preferred decoder for the
    // format's MIME type, according to the MediaCodecSelector.
    MediaCodecInfo decoderInfo = decoderInfos.get(0);
    boolean isFormatSupported = decoderInfo.isFormatSupported(format);
    boolean isPreferredDecoder = true;
    if (!isFormatSupported) {
        // Check whether any of the other decoders support the format.
        for (int i = 1; i < decoderInfos.size(); i++) {
            MediaCodecInfo otherDecoderInfo = decoderInfos.get(i);
            if (otherDecoderInfo.isFormatSupported(format)) {
                decoderInfo = otherDecoderInfo;
                isFormatSupported = true;
                isPreferredDecoder = false;
                break;
            }
        }
    }
    @C.FormatSupport int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES;
    @AdaptiveSupport int adaptiveSupport = isFormatSupported && decoderInfo.isSeamlessAdaptationSupported(format) ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS;
    @HardwareAccelerationSupport int hardwareAccelerationSupport = decoderInfo.hardwareAccelerated ? HARDWARE_ACCELERATION_SUPPORTED : HARDWARE_ACCELERATION_NOT_SUPPORTED;
    @DecoderSupport int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK;
    return RendererCapabilities.create(formatSupport, adaptiveSupport, tunnelingSupport, hardwareAccelerationSupport, decoderSupport);
}
Also used : MediaCodecInfo(androidx.media3.exoplayer.mediacodec.MediaCodecInfo) SuppressLint(android.annotation.SuppressLint) RendererCapabilities(androidx.media3.exoplayer.RendererCapabilities)

Example 3 with DecoderQueryException

use of androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException in project media by androidx.

the class MediaCodecVideoRenderer method supportsFormat.

@Override
@Capabilities
protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format) throws DecoderQueryException {
    String mimeType = format.sampleMimeType;
    if (!MimeTypes.isVideo(mimeType)) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
    }
    @Nullable DrmInitData drmInitData = format.drmInitData;
    // Assume encrypted content requires secure decoders.
    boolean requiresSecureDecryption = drmInitData != null;
    List<MediaCodecInfo> decoderInfos = getDecoderInfos(mediaCodecSelector, format, requiresSecureDecryption, /* requiresTunnelingDecoder= */
    false);
    if (requiresSecureDecryption && decoderInfos.isEmpty()) {
        // No secure decoders are available. Fall back to non-secure decoders.
        decoderInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */
        false, /* requiresTunnelingDecoder= */
        false);
    }
    if (decoderInfos.isEmpty()) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
    }
    if (!supportsFormatDrm(format)) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_DRM);
    }
    // Check whether the first decoder supports the format. This is the preferred decoder for the
    // format's MIME type, according to the MediaCodecSelector.
    MediaCodecInfo decoderInfo = decoderInfos.get(0);
    boolean isFormatSupported = decoderInfo.isFormatSupported(format);
    boolean isPreferredDecoder = true;
    if (!isFormatSupported) {
        // Check whether any of the other decoders support the format.
        for (int i = 1; i < decoderInfos.size(); i++) {
            MediaCodecInfo otherDecoderInfo = decoderInfos.get(i);
            if (otherDecoderInfo.isFormatSupported(format)) {
                decoderInfo = otherDecoderInfo;
                isFormatSupported = true;
                isPreferredDecoder = false;
                break;
            }
        }
    }
    @C.FormatSupport int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES;
    @AdaptiveSupport int adaptiveSupport = decoderInfo.isSeamlessAdaptationSupported(format) ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS;
    @HardwareAccelerationSupport int hardwareAccelerationSupport = decoderInfo.hardwareAccelerated ? HARDWARE_ACCELERATION_SUPPORTED : HARDWARE_ACCELERATION_NOT_SUPPORTED;
    @DecoderSupport int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK;
    @TunnelingSupport int tunnelingSupport = TUNNELING_NOT_SUPPORTED;
    if (isFormatSupported) {
        List<MediaCodecInfo> tunnelingDecoderInfos = getDecoderInfos(mediaCodecSelector, format, requiresSecureDecryption, /* requiresTunnelingDecoder= */
        true);
        if (!tunnelingDecoderInfos.isEmpty()) {
            MediaCodecInfo tunnelingDecoderInfo = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(tunnelingDecoderInfos, format).get(0);
            if (tunnelingDecoderInfo.isFormatSupported(format) && tunnelingDecoderInfo.isSeamlessAdaptationSupported(format)) {
                tunnelingSupport = TUNNELING_SUPPORTED;
            }
        }
    }
    return RendererCapabilities.create(formatSupport, adaptiveSupport, tunnelingSupport, hardwareAccelerationSupport, decoderSupport);
}
Also used : DrmInitData(androidx.media3.common.DrmInitData) MediaCodecInfo(androidx.media3.exoplayer.mediacodec.MediaCodecInfo) Nullable(androidx.annotation.Nullable) SuppressLint(android.annotation.SuppressLint) Point(android.graphics.Point) CodecCapabilities(android.media.MediaCodecInfo.CodecCapabilities) RendererCapabilities(androidx.media3.exoplayer.RendererCapabilities)

Example 4 with DecoderQueryException

use of androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException in project media by androidx.

the class MediaCodecVideoRenderer method getCodecMaxSize.

/**
 * Returns a maximum video size to use when configuring a codec for {@code format} in a way that
 * will allow possible adaptation to other compatible formats that are expected to have the same
 * aspect ratio, but whose sizes are unknown.
 *
 * @param codecInfo Information about the {@link MediaCodec} being configured.
 * @param format The {@link Format} for which the codec is being configured.
 * @return The maximum video size to use, or null if the size of {@code format} should be used.
 */
private static Point getCodecMaxSize(MediaCodecInfo codecInfo, Format format) {
    boolean isVerticalVideo = format.height > format.width;
    int formatLongEdgePx = isVerticalVideo ? format.height : format.width;
    int formatShortEdgePx = isVerticalVideo ? format.width : format.height;
    float aspectRatio = (float) formatShortEdgePx / formatLongEdgePx;
    for (int longEdgePx : STANDARD_LONG_EDGE_VIDEO_PX) {
        int shortEdgePx = (int) (longEdgePx * aspectRatio);
        if (longEdgePx <= formatLongEdgePx || shortEdgePx <= formatShortEdgePx) {
            // Don't return a size not larger than the format for which the codec is being configured.
            return null;
        } else if (Util.SDK_INT >= 21) {
            Point alignedSize = codecInfo.alignVideoSizeV21(isVerticalVideo ? shortEdgePx : longEdgePx, isVerticalVideo ? longEdgePx : shortEdgePx);
            float frameRate = format.frameRate;
            if (codecInfo.isVideoSizeAndRateSupportedV21(alignedSize.x, alignedSize.y, frameRate)) {
                return alignedSize;
            }
        } else {
            try {
                // Conservatively assume the codec requires 16px width and height alignment.
                longEdgePx = Util.ceilDivide(longEdgePx, 16) * 16;
                shortEdgePx = Util.ceilDivide(shortEdgePx, 16) * 16;
                if (longEdgePx * shortEdgePx <= MediaCodecUtil.maxH264DecodableFrameSize()) {
                    return new Point(isVerticalVideo ? shortEdgePx : longEdgePx, isVerticalVideo ? longEdgePx : shortEdgePx);
                }
            } catch (DecoderQueryException e) {
                // We tried our best. Give up!
                return null;
            }
        }
    }
    return null;
}
Also used : DecoderQueryException(androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException) Point(android.graphics.Point) SuppressLint(android.annotation.SuppressLint) Point(android.graphics.Point)

Example 5 with DecoderQueryException

use of androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException in project media by androidx.

the class MediaCodecAudioRenderer method getDecoderInfos.

/**
 * Returns a list of decoders that can decode media in the specified format, in the priority order
 * specified by the {@link MediaCodecSelector}. Note that since the {@link MediaCodecSelector}
 * only has access to {@link Format#sampleMimeType}, the list is not ordered to account for
 * whether each decoder supports the details of the format (e.g., taking into account the format's
 * profile, level, channel count and so on). {@link
 * MediaCodecUtil#getDecoderInfosSortedByFormatSupport} can be used to further sort the list into
 * an order where decoders that fully support the format come first.
 *
 * @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 audioSink The {@link AudioSink} to which audio will be output.
 * @return A list of {@link MediaCodecInfo}s corresponding to decoders. May be empty.
 * @throws DecoderQueryException Thrown if there was an error querying decoders.
 */
private static List<MediaCodecInfo> getDecoderInfos(MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder, AudioSink audioSink) throws DecoderQueryException {
    @Nullable String mimeType = format.sampleMimeType;
    if (mimeType == null) {
        return ImmutableList.of();
    }
    if (audioSink.supportsFormat(format)) {
        // The format is supported directly, so a codec is only needed for decryption.
        @Nullable MediaCodecInfo codecInfo = MediaCodecUtil.getDecryptOnlyDecoderInfo();
        if (codecInfo != null) {
            return ImmutableList.of(codecInfo);
        }
    }
    List<MediaCodecInfo> decoderInfos = mediaCodecSelector.getDecoderInfos(mimeType, requiresSecureDecoder, /* requiresTunnelingDecoder= */
    false);
    @Nullable String alternativeMimeType = MediaCodecUtil.getAlternativeCodecMimeType(format);
    if (alternativeMimeType == null) {
        return ImmutableList.copyOf(decoderInfos);
    }
    List<MediaCodecInfo> alternativeDecoderInfos = mediaCodecSelector.getDecoderInfos(alternativeMimeType, requiresSecureDecoder, /* requiresTunnelingDecoder= */
    false);
    return ImmutableList.<MediaCodecInfo>builder().addAll(decoderInfos).addAll(alternativeDecoderInfos).build();
}
Also used : MediaCodecInfo(androidx.media3.exoplayer.mediacodec.MediaCodecInfo) Nullable(androidx.annotation.Nullable)

Aggregations

MediaCodecInfo (androidx.media3.exoplayer.mediacodec.MediaCodecInfo)4 SuppressLint (android.annotation.SuppressLint)3 Point (android.graphics.Point)2 CodecCapabilities (android.media.MediaCodecInfo.CodecCapabilities)2 Nullable (androidx.annotation.Nullable)2 RendererCapabilities (androidx.media3.exoplayer.RendererCapabilities)2 DrmInitData (androidx.media3.common.DrmInitData)1 DecoderQueryException (androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException)1