mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Roll forward of 651fa0dbb7.
Reason for not rolling back the rollback 9151103968: 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
298e15eab4
commit
361d9b1783
2 changed files with 58 additions and 6 deletions
|
|
@ -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 {
|
||||||
/* 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 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;
|
||||||
/** 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 {
|
||||||
: 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…
Reference in a new issue