Roll forward of 2ed1deb52d.

Reason for not rolling back the rollback d68b790077: file name changed and
file content moved, the automated tool is unable to correctly apply the change.

Apply suggested AVC profile depending on the API version.

Use `AVCProfileHigh` only when there's encoder support.

PiperOrigin-RevId: 426363780
This commit is contained in:
claincly 2022-02-04 11:50:06 +00:00 committed by Ian Baker
parent 9a5238b0f7
commit f6baffc490
2 changed files with 58 additions and 6 deletions

View File

@ -31,6 +31,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
@ -119,29 +120,65 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
/* mediaCodecName= */ null); /* mediaCodecName= */ null);
} }
MediaCodecInfo encoderInfo = encoderAndClosestFormatSupport.first;
format = encoderAndClosestFormatSupport.second; format = encoderAndClosestFormatSupport.second;
MediaFormat mediaFormat = String mimeType = checkNotNull(format.sampleMimeType);
MediaFormat.createVideoFormat( MediaFormat mediaFormat = MediaFormat.createVideoFormat(mimeType, format.width, format.height);
checkNotNull(format.sampleMimeType), format.width, format.height);
mediaFormat.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate); mediaFormat.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.averageBitrate); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.averageBitrate);
@Nullable @Nullable
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format); Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
if (codecProfileAndLevel != null) { if (codecProfileAndLevel != null) {
// The codecProfileAndLevel is supported by the encoder.
mediaFormat.setInteger(MediaFormat.KEY_PROFILE, codecProfileAndLevel.first); mediaFormat.setInteger(MediaFormat.KEY_PROFILE, codecProfileAndLevel.first);
if (SDK_INT >= 23) { if (SDK_INT >= 23) {
mediaFormat.setInteger(MediaFormat.KEY_LEVEL, codecProfileAndLevel.second); mediaFormat.setInteger(MediaFormat.KEY_LEVEL, codecProfileAndLevel.second);
} }
} }
// TODO(b/210593256): Remove overriding profile/level (before API 29) after switching to in-app
// muxing.
if (mimeType.equals(MimeTypes.VIDEO_H264)) {
// Applying suggested profile/level settings from
// https://developer.android.com/guide/topics/media/sharing-video#b-frames_and_encoding_profiles
if (Util.SDK_INT >= 29) {
if (EncoderUtil.isProfileLevelSupported(
encoderInfo,
mimeType,
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
EncoderUtil.LEVEL_UNSET)) {
// Use the highest supported profile and use B-frames.
mediaFormat.setInteger(
MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh);
mediaFormat.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 1);
}
} else if (Util.SDK_INT >= 26) {
if (EncoderUtil.isProfileLevelSupported(
encoderInfo,
mimeType,
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
EncoderUtil.LEVEL_UNSET)) {
// Use the highest-supported profile, but disable the generation of B-frames. This
// accommodates some limitations in the MediaMuxer in these system versions.
mediaFormat.setInteger(
MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh);
mediaFormat.setInteger(MediaFormat.KEY_LATENCY, 1);
}
} else {
// Use the baseline profile for safest results.
mediaFormat.setInteger(
MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline);
}
}
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, DEFAULT_COLOR_FORMAT); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, DEFAULT_COLOR_FORMAT);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL_SECS); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL_SECS);
return createCodec( return createCodec(
format, format,
mediaFormat, mediaFormat,
encoderAndClosestFormatSupport.first.getName(), encoderInfo.getName(),
/* isVideo= */ true, /* isVideo= */ true,
/* isDecoder= */ false, /* isDecoder= */ false,
/* outputSurface= */ null); /* outputSurface= */ null);

View File

@ -25,6 +25,7 @@ import android.util.Pair;
import androidx.annotation.DoNotInline; import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -37,6 +38,9 @@ import java.util.List;
@UnstableApi @UnstableApi
public final class EncoderUtil { 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 List<MediaCodecInfo> encoders = new ArrayList<>();
/** /**
@ -108,14 +112,25 @@ public final class EncoderUtil {
: null; : null;
} }
/** Returns whether the {@link MediaCodecInfo encoder} supports the given profile and level. */ /**
* Checks whether the {@link MediaCodecInfo encoder} supports the given profile and level.
*
* @param encoderInfo The {@link MediaCodecInfo encoderInfo}.
* @param mimeType The {@link MimeTypes MIME type}.
* @param profile The encoding profile.
* @param level The encoding level, specify {@link #LEVEL_UNSET} if checking whether the encoder
* supports a specific profile.
* @return Whether the profile and level (if set) is supported by the encoder.
*/
public static boolean isProfileLevelSupported( public static boolean isProfileLevelSupported(
MediaCodecInfo encoderInfo, String mimeType, int profile, int level) { MediaCodecInfo encoderInfo, String mimeType, int profile, int level) {
// TODO(b/214964116): Merge into MediaCodecUtil.
MediaCodecInfo.CodecProfileLevel[] profileLevels = MediaCodecInfo.CodecProfileLevel[] profileLevels =
encoderInfo.getCapabilitiesForType(mimeType).profileLevels; encoderInfo.getCapabilitiesForType(mimeType).profileLevels;
for (MediaCodecInfo.CodecProfileLevel profileLevel : profileLevels) { for (MediaCodecInfo.CodecProfileLevel profileLevel : profileLevels) {
if (profileLevel.profile == profile && profileLevel.level == level) { if (profileLevel.profile == profile
&& (level == LEVEL_UNSET || profileLevel.level == level)) {
return true; return true;
} }
} }