Commit d767be4c by claincly Committed by Ian Baker

Add format fallback ranking.

Introduce an interface EncoderSelector for developers to filter out unwanted
encoders.

PiperOrigin-RevId: 425611421
parent fc528ebe
...@@ -47,7 +47,7 @@ public final class Codec { ...@@ -47,7 +47,7 @@ public final class Codec {
public interface DecoderFactory { public interface DecoderFactory {
/** A default {@code DecoderFactory} implementation. */ /** A default {@code DecoderFactory} implementation. */
DecoderFactory DEFAULT = new DefaultCodecFactory(); DecoderFactory DEFAULT = new DefaultCodecFactory(/* videoEncoderSelector= */ null);
/** /**
* Returns a {@link Codec} for audio decoding. * Returns a {@link Codec} for audio decoding.
...@@ -76,7 +76,7 @@ public final class Codec { ...@@ -76,7 +76,7 @@ public final class Codec {
public interface EncoderFactory { public interface EncoderFactory {
/** A default {@code EncoderFactory} implementation. */ /** A default {@code EncoderFactory} implementation. */
EncoderFactory DEFAULT = new DefaultCodecFactory(); EncoderFactory DEFAULT = new DefaultCodecFactory(EncoderSelector.DEFAULT);
/** /**
* Returns a {@link Codec} for audio encoding. * Returns a {@link Codec} for audio encoding.
......
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.transformer;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.List;
/** Selector of {@link MediaCodec} encoder instances. */
public interface EncoderSelector {
/**
* Default implementation of {@link EncoderSelector}, which returns the preferred encoders for the
* given {@link MimeTypes MIME type}.
*/
EncoderSelector DEFAULT = EncoderUtil::getSupportedEncoders;
/**
* Returns a list of encoders that can encode media in the specified {@code mimeType}, in priority
* order.
*
* @param mimeType The {@link MimeTypes MIME type} for which an encoder is required.
* @return An unmodifiable list of {@link MediaCodecInfo encoders} that supports the {@code
* mimeType}. The list may be empty.
*/
List<MediaCodecInfo> selectEncoderInfos(String mimeType);
}
...@@ -22,7 +22,11 @@ import android.media.MediaCodec; ...@@ -22,7 +22,11 @@ import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaCodecList; import android.media.MediaCodecList;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -128,6 +132,42 @@ public final class EncoderUtil { ...@@ -128,6 +132,42 @@ public final class EncoderUtil {
.clamp(bitrate); .clamp(bitrate);
} }
/** Checks if a {@link MediaCodecInfo codec} is hardware-accelerated. */
public static boolean isHardwareAccelerated(MediaCodecInfo encoderInfo, String mimeType) {
// TODO(b/214964116): Merge into MediaCodecUtil.
if (Util.SDK_INT >= 29) {
return Api29.isHardwareAccelerated(encoderInfo);
}
// codecInfo.isHardwareAccelerated() == !codecInfo.isSoftwareOnly() is not necessarily true.
// However, we assume this to be true as an approximation.
return !isSoftwareOnly(encoderInfo, mimeType);
}
private static boolean isSoftwareOnly(MediaCodecInfo encoderInfo, String mimeType) {
if (Util.SDK_INT >= 29) {
return Api29.isSoftwareOnly(encoderInfo);
}
if (MimeTypes.isAudio(mimeType)) {
// Assume audio decoders are software only.
return true;
}
String codecName = Ascii.toLowerCase(encoderInfo.getName());
if (codecName.startsWith("arc.")) {
// App Runtime for Chrome (ARC) codecs
return false;
}
// Estimate whether a codec is software-only, to emulate isSoftwareOnly on API < 29.
return codecName.startsWith("omx.google.")
|| codecName.startsWith("omx.ffmpeg.")
|| (codecName.startsWith("omx.sec.") && codecName.contains(".sw."))
|| codecName.equals("omx.qcom.video.decoder.hevcswvdec")
|| codecName.startsWith("c2.android.")
|| codecName.startsWith("c2.google.")
|| (!codecName.startsWith("omx.") && !codecName.startsWith("c2."));
}
/** /**
* Align to the closest resolution that respects the encoder's supported alignment. * Align to the closest resolution that respects the encoder's supported alignment.
* *
...@@ -152,5 +192,18 @@ public final class EncoderUtil { ...@@ -152,5 +192,18 @@ public final class EncoderUtil {
} }
} }
@RequiresApi(29)
private static final class Api29 {
@DoNotInline
public static boolean isHardwareAccelerated(MediaCodecInfo encoderInfo) {
return encoderInfo.isHardwareAccelerated();
}
@DoNotInline
public static boolean isSoftwareOnly(MediaCodecInfo encoderInfo) {
return encoderInfo.isSoftwareOnly();
}
}
private EncoderUtil() {} private EncoderUtil() {}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment