mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Pass format instead of codec string when getting profile and level
AV1 profile recognition requires additional info contained in format. PiperOrigin-RevId: 258746315
This commit is contained in:
parent
c779e84cbb
commit
e25340be3d
4 changed files with 71 additions and 37 deletions
|
|
@ -198,7 +198,7 @@ public final class MediaCodecInfo {
|
||||||
* @throws MediaCodecUtil.DecoderQueryException Thrown if an error occurs while querying decoders.
|
* @throws MediaCodecUtil.DecoderQueryException Thrown if an error occurs while querying decoders.
|
||||||
*/
|
*/
|
||||||
public boolean isFormatSupported(Format format) throws MediaCodecUtil.DecoderQueryException {
|
public boolean isFormatSupported(Format format) throws MediaCodecUtil.DecoderQueryException {
|
||||||
if (!isCodecSupported(format.codecs)) {
|
if (!isCodecSupported(format)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,25 +226,25 @@ public final class MediaCodecInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the decoder supports the given {@code codec}. If there is insufficient information to
|
* Whether the decoder supports the codec of the given {@code format}. If there is insufficient
|
||||||
* decide, returns true.
|
* information to decide, returns true.
|
||||||
*
|
*
|
||||||
* @param codec Codec string as defined in RFC 6381.
|
* @param format The input media format.
|
||||||
* @return True if the given codec is supported by the decoder.
|
* @return True if the codec of the given {@code format} is supported by the decoder.
|
||||||
*/
|
*/
|
||||||
public boolean isCodecSupported(String codec) {
|
public boolean isCodecSupported(Format format) {
|
||||||
if (codec == null || mimeType == null) {
|
if (format.codecs == null || mimeType == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String codecMimeType = MimeTypes.getMediaMimeType(codec);
|
String codecMimeType = MimeTypes.getMediaMimeType(format.codecs);
|
||||||
if (codecMimeType == null) {
|
if (codecMimeType == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!mimeType.equals(codecMimeType)) {
|
if (!mimeType.equals(codecMimeType)) {
|
||||||
logNoSupport("codec.mime " + codec + ", " + codecMimeType);
|
logNoSupport("codec.mime " + format.codecs + ", " + codecMimeType);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codec);
|
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||||
if (codecProfileAndLevel == null) {
|
if (codecProfileAndLevel == null) {
|
||||||
// If we don't know any better, we assume that the profile and level are supported.
|
// If we don't know any better, we assume that the profile and level are supported.
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -261,7 +261,7 @@ public final class MediaCodecInfo {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logNoSupport("codec.profileLevel, " + codec + ", " + codecMimeType);
|
logNoSupport("codec.profileLevel, " + format.codecs + ", " + codecMimeType);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,8 +279,7 @@ public final class MediaCodecInfo {
|
||||||
if (isVideo) {
|
if (isVideo) {
|
||||||
return adaptive;
|
return adaptive;
|
||||||
} else {
|
} else {
|
||||||
Pair<Integer, Integer> codecProfileLevel =
|
Pair<Integer, Integer> codecProfileLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||||
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
|
|
||||||
return codecProfileLevel != null && codecProfileLevel.first == CodecProfileLevel.AACObjectXHE;
|
return codecProfileLevel != null && codecProfileLevel.first == CodecProfileLevel.AACObjectXHE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -314,9 +313,9 @@ public final class MediaCodecInfo {
|
||||||
}
|
}
|
||||||
// Check the codec profile levels support adaptation.
|
// Check the codec profile levels support adaptation.
|
||||||
Pair<Integer, Integer> oldCodecProfileLevel =
|
Pair<Integer, Integer> oldCodecProfileLevel =
|
||||||
MediaCodecUtil.getCodecProfileAndLevel(oldFormat.codecs);
|
MediaCodecUtil.getCodecProfileAndLevel(oldFormat);
|
||||||
Pair<Integer, Integer> newCodecProfileLevel =
|
Pair<Integer, Integer> newCodecProfileLevel =
|
||||||
MediaCodecUtil.getCodecProfileAndLevel(newFormat.codecs);
|
MediaCodecUtil.getCodecProfileAndLevel(newFormat);
|
||||||
if (oldCodecProfileLevel == null || newCodecProfileLevel == null) {
|
if (oldCodecProfileLevel == null || newCodecProfileLevel == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -230,35 +230,34 @@ public final class MediaCodecUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the given
|
* Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the codec
|
||||||
* codec description string (as defined by RFC 6381).
|
* description string (as defined by RFC 6381) of the given format.
|
||||||
*
|
*
|
||||||
* @param codec A codec description string, as defined by RFC 6381, or {@code null} if not known.
|
* @param format Media format with a codec description string, as defined by RFC 6381.
|
||||||
* @return A pair (profile constant, level constant) if {@code codec} is well-formed and
|
* @return A pair (profile constant, level constant) if the codec of the {@code format} is
|
||||||
* recognized, or null otherwise
|
* well-formed and recognized, or null otherwise.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
public static Pair<Integer, Integer> getCodecProfileAndLevel(Format format) {
|
||||||
public static Pair<Integer, Integer> getCodecProfileAndLevel(@Nullable String codec) {
|
if (format.codecs == null) {
|
||||||
if (codec == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String[] parts = codec.split("\\.");
|
String[] parts = format.codecs.split("\\.");
|
||||||
switch (parts[0]) {
|
switch (parts[0]) {
|
||||||
case CODEC_ID_AVC1:
|
case CODEC_ID_AVC1:
|
||||||
case CODEC_ID_AVC2:
|
case CODEC_ID_AVC2:
|
||||||
return getAvcProfileAndLevel(codec, parts);
|
return getAvcProfileAndLevel(format.codecs, parts);
|
||||||
case CODEC_ID_VP09:
|
case CODEC_ID_VP09:
|
||||||
return getVp9ProfileAndLevel(codec, parts);
|
return getVp9ProfileAndLevel(format.codecs, parts);
|
||||||
case CODEC_ID_HEV1:
|
case CODEC_ID_HEV1:
|
||||||
case CODEC_ID_HVC1:
|
case CODEC_ID_HVC1:
|
||||||
return getHevcProfileAndLevel(codec, parts);
|
return getHevcProfileAndLevel(format.codecs, parts);
|
||||||
case CODEC_ID_DVHE:
|
case CODEC_ID_DVHE:
|
||||||
case CODEC_ID_DVH1:
|
case CODEC_ID_DVH1:
|
||||||
return getDolbyVisionProfileAndLevel(codec, parts);
|
return getDolbyVisionProfileAndLevel(format.codecs, parts);
|
||||||
case CODEC_ID_AV01:
|
case CODEC_ID_AV01:
|
||||||
return getAv1ProfileAndLevel(codec, parts);
|
return getAv1ProfileAndLevel(format.codecs, parts);
|
||||||
case CODEC_ID_MP4A:
|
case CODEC_ID_MP4A:
|
||||||
return getAacCodecProfileAndLevel(codec, parts);
|
return getAacCodecProfileAndLevel(format.codecs, parts);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -390,8 +390,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
||||||
decoderInfos = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(decoderInfos, format);
|
decoderInfos = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(decoderInfos, format);
|
||||||
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
|
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
|
||||||
// Fallback to primary decoders for H.265/HEVC or H.264/AVC for the relevant DV profiles.
|
// Fallback to primary decoders for H.265/HEVC or H.264/AVC for the relevant DV profiles.
|
||||||
Pair<Integer, Integer> codecProfileAndLevel =
|
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||||
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
|
|
||||||
if (codecProfileAndLevel != null) {
|
if (codecProfileAndLevel != null) {
|
||||||
int profile = codecProfileAndLevel.first;
|
int profile = codecProfileAndLevel.first;
|
||||||
if (profile == 4 || profile == 8) {
|
if (profile == 4 || profile == 8) {
|
||||||
|
|
@ -1194,8 +1193,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
||||||
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
|
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
|
||||||
// Some phones require the profile to be set on the codec.
|
// Some phones require the profile to be set on the codec.
|
||||||
// See https://github.com/google/ExoPlayer/pull/5438.
|
// See https://github.com/google/ExoPlayer/pull/5438.
|
||||||
Pair<Integer, Integer> codecProfileAndLevel =
|
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||||
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
|
|
||||||
if (codecProfileAndLevel != null) {
|
if (codecProfileAndLevel != null) {
|
||||||
MediaFormatUtil.maybeSetInteger(
|
MediaFormatUtil.maybeSetInteger(
|
||||||
mediaFormat, MediaFormat.KEY_PROFILE, codecProfileAndLevel.first);
|
mediaFormat, MediaFormat.KEY_PROFILE, codecProfileAndLevel.first);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||||
import android.media.MediaCodecInfo;
|
import android.media.MediaCodecInfo;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
|
@ -87,17 +89,53 @@ public final class MediaCodecUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCodecProfileAndLevel_rejectsNullCodecString() {
|
public void getCodecProfileAndLevel_rejectsNullCodecString() {
|
||||||
assertThat(MediaCodecUtil.getCodecProfileAndLevel(/* codec= */ null)).isNull();
|
Format format =
|
||||||
|
Format.createVideoSampleFormat(
|
||||||
|
/* id= */ null,
|
||||||
|
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
|
||||||
|
/* codecs= */ null,
|
||||||
|
/* bitrate= */ Format.NO_VALUE,
|
||||||
|
/* maxInputSize= */ Format.NO_VALUE,
|
||||||
|
/* width= */ 1024,
|
||||||
|
/* height= */ 768,
|
||||||
|
/* frameRate= */ Format.NO_VALUE,
|
||||||
|
/* initializationData= */ null,
|
||||||
|
/* drmInitData= */ null);
|
||||||
|
assertThat(MediaCodecUtil.getCodecProfileAndLevel(format)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCodecProfileAndLevel_rejectsEmptyCodecString() {
|
public void getCodecProfileAndLevel_rejectsEmptyCodecString() {
|
||||||
assertThat(MediaCodecUtil.getCodecProfileAndLevel("")).isNull();
|
Format format =
|
||||||
|
Format.createVideoSampleFormat(
|
||||||
|
/* id= */ null,
|
||||||
|
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
|
||||||
|
/* codecs= */ "",
|
||||||
|
/* bitrate= */ Format.NO_VALUE,
|
||||||
|
/* maxInputSize= */ Format.NO_VALUE,
|
||||||
|
/* width= */ 1024,
|
||||||
|
/* height= */ 768,
|
||||||
|
/* frameRate= */ Format.NO_VALUE,
|
||||||
|
/* initializationData= */ null,
|
||||||
|
/* drmInitData= */ null);
|
||||||
|
assertThat(MediaCodecUtil.getCodecProfileAndLevel(format)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertCodecProfileAndLevelForCodecsString(
|
private static void assertCodecProfileAndLevelForCodecsString(
|
||||||
String codecs, int profile, int level) {
|
String codecs, int profile, int level) {
|
||||||
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codecs);
|
Format format =
|
||||||
|
Format.createVideoSampleFormat(
|
||||||
|
/* id= */ null,
|
||||||
|
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
|
||||||
|
/* codecs= */ codecs,
|
||||||
|
/* bitrate= */ Format.NO_VALUE,
|
||||||
|
/* maxInputSize= */ Format.NO_VALUE,
|
||||||
|
/* width= */ 1024,
|
||||||
|
/* height= */ 768,
|
||||||
|
/* frameRate= */ Format.NO_VALUE,
|
||||||
|
/* initializationData= */ null,
|
||||||
|
/* drmInitData= */ null);
|
||||||
|
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||||
assertThat(codecProfileAndLevel).isNotNull();
|
assertThat(codecProfileAndLevel).isNotNull();
|
||||||
assertThat(codecProfileAndLevel.first).isEqualTo(profile);
|
assertThat(codecProfileAndLevel.first).isEqualTo(profile);
|
||||||
assertThat(codecProfileAndLevel.second).isEqualTo(level);
|
assertThat(codecProfileAndLevel.second).isEqualTo(level);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue