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:
parent
9a5238b0f7
commit
f6baffc490
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user