From 6ec18c8a208842eeb178f97e0680770b2e2a8b29 Mon Sep 17 00:00:00 2001 From: samrobinson Date: Wed, 13 Jul 2022 12:48:02 +0000 Subject: [PATCH] Fix assertion error when using high quality targeting API. Add test that verifies SSIM with API enabled. #minor-release PiperOrigin-RevId: 460692420 --- .../transformer/mh/TranscodeQualityTest.java | 15 ++++-- .../transformer/DefaultEncoderFactory.java | 46 +++++++++++-------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/mh/TranscodeQualityTest.java b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/mh/TranscodeQualityTest.java index 2a44370f3aa..1c6fc3cb83e 100644 --- a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/mh/TranscodeQualityTest.java +++ b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/mh/TranscodeQualityTest.java @@ -24,10 +24,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.transformer.AndroidTestUtil; +import com.google.android.exoplayer2.transformer.DefaultEncoderFactory; import com.google.android.exoplayer2.transformer.TransformationRequest; import com.google.android.exoplayer2.transformer.TransformationTestResult; import com.google.android.exoplayer2.transformer.Transformer; import com.google.android.exoplayer2.transformer.TransformerAndroidTestRunner; +import com.google.android.exoplayer2.transformer.VideoEncoderSettings; import com.google.android.exoplayer2.util.MimeTypes; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,9 +38,10 @@ @RunWith(AndroidJUnit4.class) public final class TranscodeQualityTest { @Test - public void transformWithDecodeEncode_ssimIsGreaterThan90Percent() throws Exception { + public void transformHighQualityTargetingAvcToAvc1920x1080_ssimIsGreaterThan95Percent() + throws Exception { Context context = ApplicationProvider.getApplicationContext(); - String testId = "transformWithDecodeEncode_ssim"; + String testId = "transformHighQualityTargetingAvcToAvc1920x1080_ssim"; if (AndroidTestUtil.skipAndLogIfInsufficientCodecSupport( context, @@ -52,7 +55,13 @@ public void transformWithDecodeEncode_ssimIsGreaterThan90Percent() throws Except new Transformer.Builder(context) .setTransformationRequest( new TransformationRequest.Builder().setVideoMimeType(MimeTypes.VIDEO_H264).build()) - .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory(context)) + .setEncoderFactory( + new DefaultEncoderFactory.Builder(context) + .setRequestedVideoEncoderSettings( + new VideoEncoderSettings.Builder() + .setEnableHighQualityTargeting(true) + .build()) + .build()) .setRemoveAudio(true) .build(); diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java index a9f034d672d..aabf78e624b 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java @@ -239,27 +239,27 @@ public Codec createForVideoEncoding(Format format, List allowedMimeTypes mimeType, encoderSupportedFormat.width, encoderSupportedFormat.height); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, round(encoderSupportedFormat.frameRate)); - int bitrate; - if (supportedVideoEncoderSettings.enableHighQualityTargeting) { - bitrate = + int bitrate = new DeviceMappedEncoderBitrateProvider() .getBitrate( encoderInfo.getName(), encoderSupportedFormat.width, encoderSupportedFormat.height, encoderSupportedFormat.frameRate); - } else if (supportedVideoEncoderSettings.bitrate != VideoEncoderSettings.NO_VALUE) { - bitrate = supportedVideoEncoderSettings.bitrate; - } else { - bitrate = + encoderSupportedFormat = + encoderSupportedFormat.buildUpon().setAverageBitrate(bitrate).build(); + } else if (encoderSupportedFormat.bitrate == Format.NO_VALUE) { + int bitrate = getSuggestedBitrate( encoderSupportedFormat.width, encoderSupportedFormat.height, encoderSupportedFormat.frameRate); + encoderSupportedFormat = + encoderSupportedFormat.buildUpon().setAverageBitrate(bitrate).build(); } - mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate); + mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, encoderSupportedFormat.averageBitrate); mediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, supportedVideoEncoderSettings.bitrateMode); if (supportedVideoEncoderSettings.profile != VideoEncoderSettings.NO_VALUE @@ -389,11 +389,23 @@ private static VideoEncoderQueryResult findEncoderWithClosestFormatSupport( return null; } + // TODO(b/238094555): Check encoder supports bitrate targeted by high quality. MediaCodecInfo pickedEncoderInfo = filteredEncoderInfos.get(0); int closestSupportedBitrate = EncoderUtil.getSupportedBitrateRange(pickedEncoderInfo, mimeType).clamp(requestedBitrate); - VideoEncoderSettings.Builder supportedEncodingSettingBuilder = - videoEncoderSettings.buildUpon().setBitrate(closestSupportedBitrate); + + VideoEncoderSettings.Builder supportedEncodingSettingBuilder = videoEncoderSettings.buildUpon(); + Format.Builder encoderSupportedFormatBuilder = + requestedFormat + .buildUpon() + .setSampleMimeType(mimeType) + .setWidth(finalResolution.getWidth()) + .setHeight(finalResolution.getHeight()); + + if (!videoEncoderSettings.enableHighQualityTargeting) { + supportedEncodingSettingBuilder.setBitrate(closestSupportedBitrate); + encoderSupportedFormatBuilder.setAverageBitrate(closestSupportedBitrate); + } if (videoEncoderSettings.profile == VideoEncoderSettings.NO_VALUE || videoEncoderSettings.level == VideoEncoderSettings.NO_VALUE @@ -404,16 +416,10 @@ private static VideoEncoderQueryResult findEncoderWithClosestFormatSupport( VideoEncoderSettings.NO_VALUE, VideoEncoderSettings.NO_VALUE); } - Format encoderSupportedFormat = - requestedFormat - .buildUpon() - .setSampleMimeType(mimeType) - .setWidth(finalResolution.getWidth()) - .setHeight(finalResolution.getHeight()) - .setAverageBitrate(closestSupportedBitrate) - .build(); return new VideoEncoderQueryResult( - pickedEncoderInfo, encoderSupportedFormat, supportedEncodingSettingBuilder.build()); + pickedEncoderInfo, + encoderSupportedFormatBuilder.build(), + supportedEncodingSettingBuilder.build()); } /** Returns a list of encoders that support the requested resolution most closely. */ @@ -648,7 +654,7 @@ private static boolean mimeTypeIsSupported( * */ private static int getSuggestedBitrate(int width, int height, float frameRate) { - // TODO(b/210591626) Refactor into a BitrateProvider. + // TODO(b/238094555) Refactor into a BitrateProvider. // Assume medium motion factor. // 1080p60 -> 16.6Mbps, 720p30 -> 3.7Mbps. return (int) (width * height * frameRate * 0.07 * 2);