Add test to evaluate performance related encoding parameters.

PiperOrigin-RevId: 439268235
This commit is contained in:
claincly 2022-04-04 11:10:32 +01:00 committed by Ian Baker
parent ffeff69236
commit 3d93484402
3 changed files with 177 additions and 3 deletions

View file

@ -0,0 +1,122 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.transformer.mh.analysis;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.content.Context;
import android.media.MediaFormat;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.exoplayer2.transformer.AndroidTestUtil;
import com.google.android.exoplayer2.transformer.DefaultEncoderFactory;
import com.google.android.exoplayer2.transformer.EncoderSelector;
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.Util;
import com.google.common.collect.ImmutableList;
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
/** Instrumentation tests for analyzing encoder performance settings. */
@RunWith(Parameterized.class)
public class EncoderPerformanceAnalysisTest {
/** A non-realtime {@link MediaFormat#KEY_PRIORITY encoder priority}. */
private static final int MEDIA_CODEC_PRIORITY_NON_REALTIME = 0;
/** A realtime {@link MediaFormat#KEY_PRIORITY encoder priority}. */
private static final int MEDIA_CODEC_PRIORITY_REALTIME = 1;
private static final ImmutableList<String> INPUT_FILES =
ImmutableList.of(
AndroidTestUtil.MP4_ASSET_WITH_INCREASING_TIMESTAMPS_URI_STRING,
AndroidTestUtil.MP4_REMOTE_4K60_PORTRAIT_URI_STRING);
private static final ImmutableList<Integer> OPERATING_RATE_SETTINGS =
ImmutableList.of(VideoEncoderSettings.NO_VALUE, 30, Integer.MAX_VALUE);
private static final ImmutableList<Integer> PRIORITY_SETTINGS =
ImmutableList.of(
// Use NO_VALUE to skip setting priority.
VideoEncoderSettings.NO_VALUE,
MEDIA_CODEC_PRIORITY_NON_REALTIME,
MEDIA_CODEC_PRIORITY_REALTIME);
@Parameter(0)
public @MonotonicNonNull String fileUri;
@Parameter(1)
public int operatingRate;
@Parameter(2)
public int priority;
@Parameters(name = "analyzePerformance_{0}_OpRate={1}_Priority={2}")
public static ImmutableList<Object[]> parameters() {
ImmutableList.Builder<Object[]> parametersBuilder = new ImmutableList.Builder<>();
for (int i = 0; i < INPUT_FILES.size(); i++) {
for (int j = 0; j < OPERATING_RATE_SETTINGS.size(); j++) {
for (int k = 0; k < PRIORITY_SETTINGS.size(); k++) {
parametersBuilder.add(
new Object[] {
INPUT_FILES.get(i), OPERATING_RATE_SETTINGS.get(j), PRIORITY_SETTINGS.get(k)
});
}
}
}
return parametersBuilder.build();
}
@Test
public void analyzeEncoderPerformance() throws Exception {
checkNotNull(fileUri);
String filename = checkNotNull(Uri.parse(fileUri).getLastPathSegment());
String testId =
Util.formatInvariant(
"analyzePerformance_%s_OpRate_%d_Priority_%d", filename, operatingRate, priority);
Map<String, Object> inputValues = new HashMap<>();
inputValues.put("inputFilename", filename);
inputValues.put("operatingRate", operatingRate);
inputValues.put("priority", priority);
Context context = ApplicationProvider.getApplicationContext();
Transformer transformer =
new Transformer.Builder(context)
.setRemoveAudio(true)
.setEncoderFactory(
new DefaultEncoderFactory(
EncoderSelector.DEFAULT,
new VideoEncoderSettings.Builder()
.setEncoderPerformanceParameters(operatingRate, priority)
.build(),
/* enableFallback= */ false))
.build();
new TransformerAndroidTestRunner.Builder(context, transformer)
.setInputValues(inputValues)
.build()
.run(testId, fileUri);
}
}

View file

@ -183,6 +183,17 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
mediaFormat.setFloat(
MediaFormat.KEY_I_FRAME_INTERVAL, supportedVideoEncoderSettings.iFrameIntervalSeconds);
if (Util.SDK_INT >= 23) {
// Setting operating rate and priority is supported from API 23.
if (supportedVideoEncoderSettings.operatingRate != VideoEncoderSettings.NO_VALUE) {
mediaFormat.setInteger(
MediaFormat.KEY_OPERATING_RATE, supportedVideoEncoderSettings.operatingRate);
}
if (supportedVideoEncoderSettings.priority != VideoEncoderSettings.NO_VALUE) {
mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, supportedVideoEncoderSettings.priority);
}
}
return new DefaultCodec(
format,
mediaFormat,

View file

@ -21,8 +21,10 @@ import static java.lang.annotation.ElementType.TYPE_USE;
import android.annotation.SuppressLint;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.Format;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@ -74,6 +76,8 @@ public final class VideoEncoderSettings {
private int level;
private int colorProfile;
private float iFrameIntervalSeconds;
private int operatingRate;
private int priority;
/** Creates a new instance. */
public Builder() {
@ -83,6 +87,8 @@ public final class VideoEncoderSettings {
this.level = NO_VALUE;
this.colorProfile = DEFAULT_COLOR_PROFILE;
this.iFrameIntervalSeconds = DEFAULT_I_FRAME_INTERVAL_SECONDS;
this.operatingRate = NO_VALUE;
this.priority = NO_VALUE;
}
private Builder(VideoEncoderSettings videoEncoderSettings) {
@ -92,6 +98,8 @@ public final class VideoEncoderSettings {
this.level = videoEncoderSettings.level;
this.colorProfile = videoEncoderSettings.colorProfile;
this.iFrameIntervalSeconds = videoEncoderSettings.iFrameIntervalSeconds;
this.operatingRate = videoEncoderSettings.operatingRate;
this.priority = videoEncoderSettings.priority;
}
/**
@ -170,10 +178,31 @@ public final class VideoEncoderSettings {
return this;
}
/**
* Sets encoding operating rate and priority. The default values are {@link #NO_VALUE}.
*
* @param operatingRate The {@link MediaFormat#KEY_OPERATING_RATE operating rate}.
* @param priority The {@link MediaFormat#KEY_PRIORITY priority}.
* @return This builder.
*/
@VisibleForTesting
public Builder setEncoderPerformanceParameters(int operatingRate, int priority) {
this.operatingRate = operatingRate;
this.priority = priority;
return this;
}
/** Builds the instance. */
public VideoEncoderSettings build() {
return new VideoEncoderSettings(
bitrate, bitrateMode, profile, level, colorProfile, iFrameIntervalSeconds);
bitrate,
bitrateMode,
profile,
level,
colorProfile,
iFrameIntervalSeconds,
operatingRate,
priority);
}
}
@ -189,6 +218,10 @@ public final class VideoEncoderSettings {
public final int colorProfile;
/** The encoding I-Frame interval in seconds. */
public final float iFrameIntervalSeconds;
/** The encoder {@link MediaFormat#KEY_OPERATING_RATE operating rate}. */
public final int operatingRate;
/** The encoder {@link MediaFormat#KEY_PRIORITY priority}. */
public final int priority;
private VideoEncoderSettings(
int bitrate,
@ -196,13 +229,17 @@ public final class VideoEncoderSettings {
int profile,
int level,
int colorProfile,
float iFrameIntervalSeconds) {
float iFrameIntervalSeconds,
int operatingRate,
int priority) {
this.bitrate = bitrate;
this.bitrateMode = bitrateMode;
this.profile = profile;
this.level = level;
this.colorProfile = colorProfile;
this.iFrameIntervalSeconds = iFrameIntervalSeconds;
this.operatingRate = operatingRate;
this.priority = priority;
}
/**
@ -226,7 +263,9 @@ public final class VideoEncoderSettings {
&& profile == that.profile
&& level == that.level
&& colorProfile == that.colorProfile
&& iFrameIntervalSeconds == that.iFrameIntervalSeconds;
&& iFrameIntervalSeconds == that.iFrameIntervalSeconds
&& operatingRate == that.operatingRate
&& priority == that.priority;
}
@Override
@ -238,6 +277,8 @@ public final class VideoEncoderSettings {
result = 31 * result + level;
result = 31 * result + colorProfile;
result = 31 * result + Float.floatToIntBits(iFrameIntervalSeconds);
result = 31 * result + operatingRate;
result = 31 * result + priority;
return result;
}
}