mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add test to query device capabilities.
PiperOrigin-RevId: 439861685
This commit is contained in:
parent
b5eba24e1f
commit
61a20d5f68
@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
@ -126,14 +127,16 @@ public final class AndroidTestUtil {
|
||||
* @param testId A unique identifier for the transformer test run.
|
||||
* @param testJson A {@link JSONObject} containing a summary of the test run.
|
||||
*/
|
||||
/* package */ static void writeTestSummaryToFile(
|
||||
Context context, String testId, JSONObject testJson) throws IOException, JSONException {
|
||||
public static void writeTestSummaryToFile(Context context, String testId, JSONObject testJson)
|
||||
throws IOException, JSONException {
|
||||
testJson.put("testId", testId).put("device", getDeviceDetailsAsJsonObject());
|
||||
|
||||
String analysisContents = testJson.toString(/* indentSpaces= */ 2);
|
||||
|
||||
// Log contents as well as writing to file, for easier visibility on individual device testing.
|
||||
Log.i(testId, analysisContents);
|
||||
for (String line : Util.split(analysisContents, "\n")) {
|
||||
Log.i(testId, line);
|
||||
}
|
||||
|
||||
File analysisFile = createExternalCacheFile(context, /* fileName= */ testId + "-result.txt");
|
||||
try (FileWriter fileWriter = new FileWriter(analysisFile)) {
|
||||
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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.mh.analysis;
|
||||
|
||||
import static android.media.MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR;
|
||||
import static android.media.MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR_FD;
|
||||
import static android.media.MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ;
|
||||
import static android.media.MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR;
|
||||
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.util.Pair;
|
||||
import android.util.Range;
|
||||
import android.util.Size;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.transformer.AndroidTestUtil;
|
||||
import com.google.android.exoplayer2.transformer.EncoderUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** An analysis test to log encoder capabilities on a device. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class EncoderCapabilityAnalysisTest {
|
||||
|
||||
// TODO(b/228167357): Remove after bumping compileApiVersion to 33.
|
||||
/** Re-definition of {@code MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing} in API33. */
|
||||
private static final String FEATURE_HdrEditing = "hdr-editing";
|
||||
/**
|
||||
* Re-definition of {@code MediaCodecInfo.CodecCapabilities.FEATURE_EncodingStatistics} in API33.
|
||||
*/
|
||||
private static final String FEATURE_EncodingStatistics = "encoding-statistics";
|
||||
|
||||
@Test
|
||||
public void logEncoderCapabilities() throws Exception {
|
||||
ImmutableSet<String> supportedVideoMimeTypes = EncoderUtil.getSupportedVideoMimeTypes();
|
||||
|
||||
// Map from MIME type to a list of maps from capability name to value.
|
||||
LinkedHashMap<String, List<Map<String, Object>>> mimeTypeToEncoderInfo = new LinkedHashMap<>();
|
||||
|
||||
for (String mimeType : supportedVideoMimeTypes) {
|
||||
ImmutableList<MediaCodecInfo> encoderInfos = EncoderUtil.getSupportedEncoders(mimeType);
|
||||
ArrayList<Map<String, Object>> encoderCapabilitiesForMimeType = new ArrayList<>();
|
||||
for (MediaCodecInfo encoderInfo : encoderInfos) {
|
||||
LinkedHashMap<String, Object> capabilities = new LinkedHashMap<>();
|
||||
capabilities.put("encoder_name", encoderInfo.getName());
|
||||
|
||||
capabilities.put(
|
||||
"is_software_encoder", !EncoderUtil.isHardwareAccelerated(encoderInfo, mimeType));
|
||||
|
||||
// Bitrate modes.
|
||||
capabilities.put(
|
||||
"supports_vbr",
|
||||
EncoderUtil.isBitrateModeSupported(encoderInfo, mimeType, BITRATE_MODE_VBR));
|
||||
capabilities.put(
|
||||
"supports_cbr",
|
||||
EncoderUtil.isBitrateModeSupported(encoderInfo, mimeType, BITRATE_MODE_CBR));
|
||||
capabilities.put(
|
||||
"supports_cq",
|
||||
EncoderUtil.isBitrateModeSupported(encoderInfo, mimeType, BITRATE_MODE_CQ));
|
||||
capabilities.put(
|
||||
"supports_cbr_fd",
|
||||
EncoderUtil.isBitrateModeSupported(encoderInfo, mimeType, BITRATE_MODE_CBR_FD));
|
||||
|
||||
capabilities.put(
|
||||
"supported_bitrate_range",
|
||||
rangeToString(EncoderUtil.getSupportedBitrateRange(encoderInfo, mimeType)));
|
||||
|
||||
// Resolution support.
|
||||
Pair<Range<Integer>, Range<Integer>> supportedResolutionRanges =
|
||||
EncoderUtil.getSupportedResolutionRanges(encoderInfo, mimeType);
|
||||
capabilities.put("supported_widths_range", rangeToString(supportedResolutionRanges.first));
|
||||
capabilities.put(
|
||||
"supported_heights_range", rangeToString(supportedResolutionRanges.second));
|
||||
|
||||
checkResolutionSupport(
|
||||
encoderInfo, mimeType, capabilities, /* width= */ 1280, /* height= */ 720);
|
||||
checkResolutionSupport(
|
||||
encoderInfo, mimeType, capabilities, /* width= */ 1920, /* height= */ 1080);
|
||||
checkResolutionSupport(
|
||||
encoderInfo, mimeType, capabilities, /* width= */ 2560, /* height= */ 1440);
|
||||
checkResolutionSupport(
|
||||
encoderInfo, mimeType, capabilities, /* width= */ 3840, /* height= */ 2160);
|
||||
|
||||
checkProfileLevelSupport(encoderInfo, mimeType, capabilities);
|
||||
|
||||
capabilities.put(
|
||||
"supported_color_profiles",
|
||||
EncoderUtil.getSupportedColorFormats(encoderInfo, mimeType));
|
||||
|
||||
capabilities.put(
|
||||
"max_supported_instances",
|
||||
Util.SDK_INT >= 23 ? EncoderUtil.getMaxSupportedInstances(encoderInfo, mimeType) : -1);
|
||||
|
||||
capabilities.put(
|
||||
"supports_qp_bounds",
|
||||
Util.SDK_INT >= 31
|
||||
&& EncoderUtil.isFeatureSupported(
|
||||
encoderInfo, mimeType, MediaCodecInfo.CodecCapabilities.FEATURE_QpBounds));
|
||||
|
||||
capabilities.put(
|
||||
"supports_hdr_editing",
|
||||
Util.SDK_INT >= 33
|
||||
&& EncoderUtil.isFeatureSupported(encoderInfo, mimeType, FEATURE_HdrEditing));
|
||||
|
||||
capabilities.put(
|
||||
"supports_encoding_statistics",
|
||||
Util.SDK_INT >= 33
|
||||
&& EncoderUtil.isFeatureSupported(
|
||||
encoderInfo, mimeType, FEATURE_EncodingStatistics));
|
||||
|
||||
encoderCapabilitiesForMimeType.add(capabilities);
|
||||
}
|
||||
mimeTypeToEncoderInfo.put(mimeType, encoderCapabilitiesForMimeType);
|
||||
}
|
||||
|
||||
JSONObject resultJson = new JSONObject();
|
||||
resultJson.put("encoder_capabilities", JSONObject.wrap(mimeTypeToEncoderInfo));
|
||||
AndroidTestUtil.writeTestSummaryToFile(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
/* testId= */ "encoderCapabilityAnalysisTest",
|
||||
resultJson);
|
||||
}
|
||||
|
||||
private static void checkResolutionSupport(
|
||||
MediaCodecInfo encoder,
|
||||
String mimeType,
|
||||
Map<String, Object> capabilities,
|
||||
int width,
|
||||
int height) {
|
||||
Range<Integer> supportedWidths =
|
||||
EncoderUtil.getSupportedResolutionRanges(encoder, mimeType).first;
|
||||
@Nullable Range<Integer> supportedHeights = null;
|
||||
if (supportedWidths.contains(width)) {
|
||||
supportedHeights = EncoderUtil.getSupportedHeights(encoder, mimeType, width);
|
||||
}
|
||||
capabilities.put(
|
||||
Util.formatInvariant("supported_heights_for_%d", width), rangeToString(supportedHeights));
|
||||
|
||||
@Nullable
|
||||
Size supportedResolution = EncoderUtil.getSupportedResolution(encoder, mimeType, width, height);
|
||||
if (supportedResolution == null) {
|
||||
supportedResolution = new Size(/* width= */ 0, /* height= */ 0);
|
||||
}
|
||||
capabilities.put(
|
||||
Util.formatInvariant("supports_%dx%d", width, height),
|
||||
(supportedResolution.getWidth() == width && supportedResolution.getHeight() == height));
|
||||
capabilities.put(
|
||||
Util.formatInvariant("fallback_%dx%d", width, height), sizeToString(supportedResolution));
|
||||
}
|
||||
|
||||
private static void checkProfileLevelSupport(
|
||||
MediaCodecInfo encoder, String mimeType, Map<String, Object> capabilities) {
|
||||
LinkedHashMap<String, String> profileToHighestSupportedLevel = new LinkedHashMap<>();
|
||||
ImmutableSet<Integer> supportedEncodingProfiles =
|
||||
EncoderUtil.findSupportedEncodingProfiles(encoder, mimeType);
|
||||
for (int profile : supportedEncodingProfiles) {
|
||||
profileToHighestSupportedLevel.put(
|
||||
String.valueOf(profile),
|
||||
String.valueOf(
|
||||
EncoderUtil.findHighestSupportedEncodingLevel(encoder, mimeType, profile)));
|
||||
}
|
||||
capabilities.put("supported_profile_levels", profileToHighestSupportedLevel);
|
||||
}
|
||||
|
||||
private static String rangeToString(@Nullable Range<Integer> range) {
|
||||
return range == null
|
||||
? "0-0"
|
||||
: Util.formatInvariant("%d-%d", range.getLower(), range.getUpper());
|
||||
}
|
||||
|
||||
private static String sizeToString(@Nullable Size size) {
|
||||
return size == null ? "0x0" : Util.formatInvariant("%dx%d", size.getWidth(), size.getHeight());
|
||||
}
|
||||
}
|
@ -267,7 +267,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
||||
|
||||
MediaCodecInfo pickedEncoder = filteredEncoders.get(0);
|
||||
int closestSupportedBitrate =
|
||||
EncoderUtil.getClosestSupportedBitrate(pickedEncoder, mimeType, requestedBitrate);
|
||||
EncoderUtil.getSupportedBitrateRange(pickedEncoder, mimeType).clamp(requestedBitrate);
|
||||
VideoEncoderSettings.Builder supportedEncodingSettingBuilder =
|
||||
videoEncoderSettings.buildUpon().setBitrate(closestSupportedBitrate);
|
||||
|
||||
@ -320,7 +320,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
||||
encoders,
|
||||
/* cost= */ (encoderInfo) -> {
|
||||
int achievableBitrate =
|
||||
EncoderUtil.getClosestSupportedBitrate(encoderInfo, mimeType, requestedBitrate);
|
||||
EncoderUtil.getSupportedBitrateRange(encoderInfo, mimeType).clamp(requestedBitrate);
|
||||
return abs(achievableBitrate - requestedBitrate);
|
||||
},
|
||||
/* filterName= */ "bitrate");
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.round;
|
||||
|
||||
@ -23,6 +24,8 @@ import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecList;
|
||||
import android.media.MediaFormat;
|
||||
import android.util.Pair;
|
||||
import android.util.Range;
|
||||
import android.util.Size;
|
||||
import androidx.annotation.DoNotInline;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -32,9 +35,12 @@ import com.google.android.exoplayer2.util.MediaFormatUtil;
|
||||
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.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
/** Utility methods for {@link MediaCodec} encoders. */
|
||||
public final class EncoderUtil {
|
||||
@ -42,26 +48,47 @@ public final class EncoderUtil {
|
||||
/** A value to indicate the encoding level is not set. */
|
||||
public static final int LEVEL_UNSET = Format.NO_VALUE;
|
||||
|
||||
private static final List<MediaCodecInfo> encoders = new ArrayList<>();
|
||||
private static final Supplier<ImmutableListMultimap<String, MediaCodecInfo>>
|
||||
MIME_TYPE_TO_ENCODERS = Suppliers.memoize(EncoderUtil::populateEncoderInfos);
|
||||
|
||||
/**
|
||||
* Returns a list of {@linkplain MediaCodecInfo encoders} that support the given {@code mimeType},
|
||||
* or an empty list if there is none.
|
||||
*/
|
||||
public static ImmutableList<MediaCodecInfo> getSupportedEncoders(String mimeType) {
|
||||
maybePopulateEncoderInfos();
|
||||
return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).get(Ascii.toLowerCase(mimeType));
|
||||
}
|
||||
|
||||
ImmutableList.Builder<MediaCodecInfo> availableEncoders = new ImmutableList.Builder<>();
|
||||
for (int i = 0; i < encoders.size(); i++) {
|
||||
MediaCodecInfo encoderInfo = encoders.get(i);
|
||||
String[] supportedMimeTypes = encoderInfo.getSupportedTypes();
|
||||
for (String supportedMimeType : supportedMimeTypes) {
|
||||
if (Ascii.equalsIgnoreCase(supportedMimeType, mimeType)) {
|
||||
availableEncoders.add(encoderInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableEncoders.build();
|
||||
/** Returns a list of video {@linkplain MimeTypes MIME types} that can be encoded. */
|
||||
public static ImmutableSet<String> getSupportedVideoMimeTypes() {
|
||||
return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Range} of supported heights for the given {@link MediaCodecInfo encoder},
|
||||
* {@linkplain MimeTypes MIME type} and {@code width}.
|
||||
*
|
||||
* @throws IllegalArgumentException When the width is not in the range of {@linkplain
|
||||
* #getSupportedResolutionRanges supported widths}.
|
||||
*/
|
||||
public static Range<Integer> getSupportedHeights(
|
||||
MediaCodecInfo encoderInfo, String mimeType, int width) {
|
||||
return encoderInfo
|
||||
.getCapabilitiesForType(mimeType)
|
||||
.getVideoCapabilities()
|
||||
.getSupportedHeightsFor(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Pair} of supported width and height {@link Range ranges} for the given {@link
|
||||
* MediaCodecInfo encoder} and {@linkplain MimeTypes MIME type}.
|
||||
*/
|
||||
public static Pair<Range<Integer>, Range<Integer>> getSupportedResolutionRanges(
|
||||
MediaCodecInfo encoderInfo, String mimeType) {
|
||||
MediaCodecInfo.VideoCapabilities videoCapabilities =
|
||||
encoderInfo.getCapabilitiesForType(mimeType).getVideoCapabilities();
|
||||
return Pair.create(
|
||||
videoCapabilities.getSupportedWidths(), videoCapabilities.getSupportedHeights());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,6 +157,22 @@ public final class EncoderUtil {
|
||||
return videoEncoderCapabilities.isSizeSupported(width, height) ? new Size(width, height) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ImmutableSet set} of supported {@linkplain MediaCodecInfo.CodecProfileLevel
|
||||
* encoding profiles} for the given {@linkplain MediaCodecInfo encoder} and {@linkplain MimeTypes
|
||||
* MIME type}.
|
||||
*/
|
||||
public static ImmutableSet<Integer> findSupportedEncodingProfiles(
|
||||
MediaCodecInfo encoderInfo, String mimeType) {
|
||||
MediaCodecInfo.CodecProfileLevel[] profileLevels =
|
||||
encoderInfo.getCapabilitiesForType(mimeType).profileLevels;
|
||||
ImmutableSet.Builder<Integer> supportedProfilesBuilder = new ImmutableSet.Builder<>();
|
||||
for (MediaCodecInfo.CodecProfileLevel profileLevel : profileLevels) {
|
||||
supportedProfilesBuilder.add(profileLevel.profile);
|
||||
}
|
||||
return supportedProfilesBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the highest supported encoding level given a profile.
|
||||
*
|
||||
@ -180,17 +223,10 @@ public final class EncoderUtil {
|
||||
return mediaCodecName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the {@linkplain MediaCodecInfo encoder}'s closest supported bitrate from the given
|
||||
* bitrate.
|
||||
*/
|
||||
public static int getClosestSupportedBitrate(
|
||||
MediaCodecInfo encoderInfo, String mimeType, int bitrate) {
|
||||
return encoderInfo
|
||||
.getCapabilitiesForType(mimeType)
|
||||
.getVideoCapabilities()
|
||||
.getBitrateRange()
|
||||
.clamp(bitrate);
|
||||
/** Returns the range of supported bitrates for the given {@linkplain MimeTypes MIME type}. */
|
||||
public static Range<Integer> getSupportedBitrateRange(
|
||||
MediaCodecInfo encoderInfo, String mimeType) {
|
||||
return encoderInfo.getCapabilitiesForType(mimeType).getVideoCapabilities().getBitrateRange();
|
||||
}
|
||||
|
||||
/** Returns whether the bitrate mode is supported by the encoder. */
|
||||
@ -202,6 +238,17 @@ public final class EncoderUtil {
|
||||
.isBitrateModeSupported(bitrateMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ImmutableList list} of supported {@linkplain
|
||||
* MediaCodecInfo.CodecCapabilities#colorFormats color formats} for the given {@linkplain
|
||||
* MediaCodecInfo encoder} and {@linkplain MimeTypes MIME type}.
|
||||
*/
|
||||
public static ImmutableList<Integer> getSupportedColorFormats(
|
||||
MediaCodecInfo encoderInfo, String mimeType) {
|
||||
return ImmutableList.copyOf(
|
||||
Ints.asList(encoderInfo.getCapabilitiesForType(mimeType).colorFormats));
|
||||
}
|
||||
|
||||
/** Checks if a {@linkplain MediaCodecInfo codec} is hardware-accelerated. */
|
||||
public static boolean isHardwareAccelerated(MediaCodecInfo encoderInfo, String mimeType) {
|
||||
// TODO(b/214964116): Merge into MediaCodecUtil.
|
||||
@ -213,6 +260,18 @@ public final class EncoderUtil {
|
||||
return !isSoftwareOnly(encoderInfo, mimeType);
|
||||
}
|
||||
|
||||
/** Returns whether a given feature is supported. */
|
||||
public static boolean isFeatureSupported(
|
||||
MediaCodecInfo encoderInfo, String mimeType, String featureName) {
|
||||
return encoderInfo.getCapabilitiesForType(mimeType).isFeatureSupported(featureName);
|
||||
}
|
||||
|
||||
/** Returns the number of max number of the supported concurrent codec instances. */
|
||||
@RequiresApi(23)
|
||||
public static int getMaxSupportedInstances(MediaCodecInfo encoderInfo, String mimeType) {
|
||||
return encoderInfo.getCapabilitiesForType(mimeType).getMaxSupportedInstances();
|
||||
}
|
||||
|
||||
private static boolean isSoftwareOnly(MediaCodecInfo encoderInfo, String mimeType) {
|
||||
if (Util.SDK_INT >= 29) {
|
||||
return Api29.isSoftwareOnly(encoderInfo);
|
||||
@ -256,18 +315,25 @@ public final class EncoderUtil {
|
||||
: alignment * Math.round((float) size / alignment);
|
||||
}
|
||||
|
||||
private static synchronized void maybePopulateEncoderInfos() {
|
||||
if (encoders.isEmpty()) {
|
||||
MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
|
||||
MediaCodecInfo[] allCodecInfos = mediaCodecList.getCodecInfos();
|
||||
private static ImmutableListMultimap<String, MediaCodecInfo> populateEncoderInfos() {
|
||||
ImmutableListMultimap.Builder<String, MediaCodecInfo> encoderInfosBuilder =
|
||||
new ImmutableListMultimap.Builder<>();
|
||||
|
||||
for (MediaCodecInfo mediaCodecInfo : allCodecInfos) {
|
||||
if (!mediaCodecInfo.isEncoder()) {
|
||||
continue;
|
||||
MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
|
||||
MediaCodecInfo[] allCodecInfos = mediaCodecList.getCodecInfos();
|
||||
|
||||
for (MediaCodecInfo mediaCodecInfo : allCodecInfos) {
|
||||
if (!mediaCodecInfo.isEncoder()) {
|
||||
continue;
|
||||
}
|
||||
String[] supportedMimeTypes = mediaCodecInfo.getSupportedTypes();
|
||||
for (String mimeType : supportedMimeTypes) {
|
||||
if (MimeTypes.isVideo(mimeType)) {
|
||||
encoderInfosBuilder.put(Ascii.toLowerCase(mimeType), mediaCodecInfo);
|
||||
}
|
||||
encoders.add(mediaCodecInfo);
|
||||
}
|
||||
}
|
||||
return encoderInfosBuilder.build();
|
||||
}
|
||||
|
||||
@RequiresApi(29)
|
||||
|
Loading…
x
Reference in New Issue
Block a user