Commit 361d9b17 by claincly Committed by Ian Baker

Roll forward of…

Roll forward of https://github.com/google/ExoPlayer/commit/651fa0dbb7c935480ab82a4ddf370b43134a45ab.

Reason for not rolling back the rollback https://github.com/google/ExoPlayer/commit/9151103968270a1c18d66abdf4b583cfafa44275: 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
parent 298e15ea
...@@ -31,6 +31,7 @@ import androidx.annotation.Nullable; ...@@ -31,6 +31,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -117,29 +118,65 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { ...@@ -117,29 +118,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; ...@@ -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 com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
...@@ -35,6 +36,9 @@ import java.util.List; ...@@ -35,6 +36,9 @@ import java.util.List;
/** Utility methods for {@link MediaCodec} encoders. */ /** Utility methods for {@link MediaCodec} encoders. */
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<>();
/** /**
...@@ -106,14 +110,25 @@ public final class EncoderUtil { ...@@ -106,14 +110,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;
} }
} }
......
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