Split parameterized android test utils into utility class.
Includes adjusting how effects are defined, to make it clearer in a test that a given ItemConfig has effects associated with it. PiperOrigin-RevId: 644684308
This commit is contained in:
parent
d27549d29a
commit
afa7935553
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 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 androidx.media3.transformer;
|
||||||
|
|
||||||
|
import static androidx.media3.common.MimeTypes.VIDEO_H265;
|
||||||
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
import static androidx.media3.transformer.AndroidTestUtil.assumeFormatsSupported;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.media3.common.C;
|
||||||
|
import androidx.media3.common.ColorInfo;
|
||||||
|
import androidx.media3.common.Format;
|
||||||
|
import androidx.media3.common.MediaItem;
|
||||||
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.transformer.AndroidTestUtil.AssetInfo;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/** Test utilities for parameterized instrumentation tests. */
|
||||||
|
/* package */ final class ParameterizedAndroidTestUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assume that the device supports the inputs and output of the sequence.
|
||||||
|
*
|
||||||
|
* <p>See {@link AndroidTestUtil#assumeFormatsSupported(Context, String, Format, Format)}.
|
||||||
|
*
|
||||||
|
* @param context The {@link Context context}.
|
||||||
|
* @param testId The test ID.
|
||||||
|
* @param sequence The {@link SequenceConfig}.
|
||||||
|
* @throws Exception If an error occurs checking device support.
|
||||||
|
*/
|
||||||
|
public static void assumeSequenceFormatsSupported(
|
||||||
|
Context context, String testId, SequenceConfig sequence) throws Exception {
|
||||||
|
checkState(!sequence.itemConfigs.isEmpty());
|
||||||
|
Format outputFormat = checkNotNull(sequence.itemConfigs.get(0).outputFormat);
|
||||||
|
for (ItemConfig item : sequence.itemConfigs) {
|
||||||
|
assumeFormatsSupported(context, testId, item.format, outputFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test parameters for an {@link EditedMediaItemSequence}. */
|
||||||
|
public static final class SequenceConfig {
|
||||||
|
public final int totalExpectedFrameCount;
|
||||||
|
public final ImmutableList<ItemConfig> itemConfigs;
|
||||||
|
|
||||||
|
public SequenceConfig(ItemConfig... itemConfigs) {
|
||||||
|
this.itemConfigs = ImmutableList.copyOf(itemConfigs);
|
||||||
|
int frameCountSum = 0;
|
||||||
|
for (ItemConfig item : itemConfigs) {
|
||||||
|
frameCountSum += item.frameCount;
|
||||||
|
}
|
||||||
|
this.totalExpectedFrameCount = frameCountSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds a {@link Composition} from the sequence configuration. */
|
||||||
|
public Composition buildComposition(Effects compositionEffects) {
|
||||||
|
ImmutableList.Builder<EditedMediaItem> editedMediaItems = new ImmutableList.Builder<>();
|
||||||
|
for (ItemConfig itemConfig : itemConfigs) {
|
||||||
|
editedMediaItems.add(itemConfig.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Composition.Builder(new EditedMediaItemSequence(editedMediaItems.build()))
|
||||||
|
.setEffects(compositionEffects)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
stringBuilder.append("Seq{");
|
||||||
|
for (ItemConfig itemConfig : itemConfigs) {
|
||||||
|
stringBuilder.append(itemConfig).append(",");
|
||||||
|
}
|
||||||
|
stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length(), "}");
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test parameters for an {@link EditedMediaItem}. */
|
||||||
|
public abstract static class ItemConfig {
|
||||||
|
public final int frameCount;
|
||||||
|
@Nullable public final Format format;
|
||||||
|
@Nullable public final Format outputFormat;
|
||||||
|
|
||||||
|
protected final Effects effects;
|
||||||
|
|
||||||
|
private final String uri;
|
||||||
|
|
||||||
|
public ItemConfig(
|
||||||
|
String uri,
|
||||||
|
int frameCount,
|
||||||
|
@Nullable Format format,
|
||||||
|
@Nullable Format outputFormat,
|
||||||
|
Effects effects) {
|
||||||
|
this.uri = uri;
|
||||||
|
this.frameCount = frameCount;
|
||||||
|
this.format = format;
|
||||||
|
this.outputFormat = outputFormat;
|
||||||
|
this.effects = effects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final EditedMediaItem build() {
|
||||||
|
EditedMediaItem.Builder builder =
|
||||||
|
new EditedMediaItem.Builder(MediaItem.fromUri(uri)).setEffects(effects);
|
||||||
|
onBuild(builder);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an {@link EditedMediaItem} is being {@linkplain #build() built}.
|
||||||
|
*
|
||||||
|
* @param builder The {@link EditedMediaItem.Builder} to optionally modify before the item is
|
||||||
|
* built.
|
||||||
|
*/
|
||||||
|
protected abstract void onBuild(EditedMediaItem.Builder builder);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Iterables.getLast(Splitter.on("/").splitToList(uri))
|
||||||
|
+ (Objects.equals(effects, Effects.EMPTY) ? "" : "-effects");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@link ItemConfig} for an SDR image {@link EditedMediaItem}. */
|
||||||
|
public static final class SdrImageItemConfig extends ItemConfig {
|
||||||
|
|
||||||
|
private final int frameRate;
|
||||||
|
private final long durationUs;
|
||||||
|
|
||||||
|
public SdrImageItemConfig(AssetInfo assetInfo, int frameCount) {
|
||||||
|
this(assetInfo, frameCount, C.MICROS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SdrImageItemConfig(AssetInfo assetInfo, int frameRate, long durationUs) {
|
||||||
|
this(assetInfo, frameRate, durationUs, Effects.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SdrImageItemConfig(
|
||||||
|
AssetInfo assetInfo, int frameRate, long durationUs, Effects effects) {
|
||||||
|
super(
|
||||||
|
assetInfo.uri,
|
||||||
|
/* frameCount= */ (int)
|
||||||
|
Util.scaleLargeValue(
|
||||||
|
frameRate, durationUs, C.MICROS_PER_SECOND, RoundingMode.CEILING),
|
||||||
|
/* format= */ assetInfo.videoFormat,
|
||||||
|
/* outputFormat= */ assetInfo
|
||||||
|
.videoFormat
|
||||||
|
.buildUpon()
|
||||||
|
// Image by default are encoded in H265 and BT709 SDR.
|
||||||
|
.setSampleMimeType(VIDEO_H265)
|
||||||
|
.setColorInfo(ColorInfo.SDR_BT709_LIMITED)
|
||||||
|
.setFrameRate(frameRate)
|
||||||
|
.build(),
|
||||||
|
effects);
|
||||||
|
this.frameRate = frameRate;
|
||||||
|
this.durationUs = durationUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBuild(EditedMediaItem.Builder builder) {
|
||||||
|
builder.setFrameRate(frameRate).setDurationUs(durationUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ItemConfig} for a video {@link EditedMediaItem}.
|
||||||
|
*
|
||||||
|
* <p>Audio is removed.
|
||||||
|
*/
|
||||||
|
public static final class VideoItemConfig extends ItemConfig {
|
||||||
|
public VideoItemConfig(AssetInfo asset, Effects effects) {
|
||||||
|
super(asset.uri, asset.videoFrameCount, asset.videoFormat, asset.videoFormat, effects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBuild(EditedMediaItem.Builder builder) {
|
||||||
|
builder.setRemoveAudio(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParameterizedAndroidTestUtil() {}
|
||||||
|
}
|
@ -14,32 +14,23 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.BT601_MP4_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.BT601_MP4_ASSET;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.JPG_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.JPG_ASSET;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.PNG_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.PNG_ASSET;
|
||||||
|
import static androidx.media3.transformer.ParameterizedAndroidTestUtil.assumeSequenceFormatsSupported;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.media3.common.C;
|
|
||||||
import androidx.media3.common.ColorInfo;
|
|
||||||
import androidx.media3.common.Format;
|
|
||||||
import androidx.media3.common.MediaItem;
|
|
||||||
import androidx.media3.common.MimeTypes;
|
|
||||||
import androidx.media3.common.util.Assertions;
|
|
||||||
import androidx.media3.common.util.Util;
|
|
||||||
import androidx.media3.effect.Presentation;
|
import androidx.media3.effect.Presentation;
|
||||||
import androidx.media3.transformer.AndroidTestUtil.AssetInfo;
|
import androidx.media3.transformer.ParameterizedAndroidTestUtil.SdrImageItemConfig;
|
||||||
|
import androidx.media3.transformer.ParameterizedAndroidTestUtil.SequenceConfig;
|
||||||
|
import androidx.media3.transformer.ParameterizedAndroidTestUtil.VideoItemConfig;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.math.RoundingMode;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TestName;
|
import org.junit.rules.TestName;
|
||||||
@ -57,12 +48,22 @@ import org.junit.runners.Parameterized.Parameters;
|
|||||||
/** Parameterized end to end {@linkplain EditedMediaItemSequence sequence} export tests. */
|
/** Parameterized end to end {@linkplain EditedMediaItemSequence sequence} export tests. */
|
||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class ParameterizedInputSequenceExportTest {
|
public class ParameterizedInputSequenceExportTest {
|
||||||
private static final ImageItemConfig PNG_ITEM =
|
private static final SdrImageItemConfig PNG_ITEM =
|
||||||
new ImageItemConfig(PNG_ASSET, /* frameCount= */ 34);
|
new SdrImageItemConfig(PNG_ASSET, /* frameCount= */ 34);
|
||||||
private static final ImageItemConfig JPG_ITEM =
|
private static final SdrImageItemConfig JPG_ITEM =
|
||||||
new ImageItemConfig(JPG_ASSET, /* frameCount= */ 41);
|
new SdrImageItemConfig(JPG_ASSET, /* frameCount= */ 41);
|
||||||
private static final VideoItemConfig BT709_ITEM = new VideoItemConfig(MP4_ASSET);
|
private static final VideoItemConfig BT709_ITEM =
|
||||||
private static final VideoItemConfig BT601_ITEM = new VideoItemConfig(BT601_MP4_ASSET);
|
new VideoItemConfig(
|
||||||
|
MP4_ASSET,
|
||||||
|
new Effects(
|
||||||
|
/* audioProcessors= */ ImmutableList.of(),
|
||||||
|
ImmutableList.of(Presentation.createForHeight(360))));
|
||||||
|
private static final VideoItemConfig BT601_ITEM =
|
||||||
|
new VideoItemConfig(
|
||||||
|
BT601_MP4_ASSET,
|
||||||
|
new Effects(
|
||||||
|
/* audioProcessors= */ ImmutableList.of(),
|
||||||
|
ImmutableList.of(Presentation.createForHeight(360))));
|
||||||
|
|
||||||
@Parameters(name = "{0}")
|
@Parameters(name = "{0}")
|
||||||
public static ImmutableList<SequenceConfig> params() {
|
public static ImmutableList<SequenceConfig> params() {
|
||||||
@ -117,161 +118,19 @@ public class ParameterizedInputSequenceExportTest {
|
|||||||
ExportTestResult result =
|
ExportTestResult result =
|
||||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
.build()
|
.build()
|
||||||
.run(testId, sequence.buildComposition());
|
.run(
|
||||||
|
testId,
|
||||||
assertThat(result.exportResult.videoFrameCount).isEqualTo(sequence.totalExpectedFrameCount);
|
sequence.buildComposition(
|
||||||
assertThat(new File(result.filePath).length()).isGreaterThan(0);
|
// Presentation of 480Wx360H is used to ensure software encoders can encode.
|
||||||
}
|
|
||||||
|
|
||||||
private static void assumeSequenceFormatsSupported(
|
|
||||||
Context context, String testId, SequenceConfig sequence) throws Exception {
|
|
||||||
Assertions.checkState(!sequence.itemConfigs.isEmpty());
|
|
||||||
Format outputFormat = Assertions.checkNotNull(sequence.itemConfigs.get(0).outputFormat);
|
|
||||||
for (ItemConfig item : sequence.itemConfigs) {
|
|
||||||
AndroidTestUtil.assumeFormatsSupported(context, testId, item.format, outputFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Test parameters for an {@link EditedMediaItemSequence}. */
|
|
||||||
private static final class SequenceConfig {
|
|
||||||
public final int totalExpectedFrameCount;
|
|
||||||
public final ImmutableList<ItemConfig> itemConfigs;
|
|
||||||
|
|
||||||
public SequenceConfig(ItemConfig... itemConfigs) {
|
|
||||||
this.itemConfigs = ImmutableList.copyOf(itemConfigs);
|
|
||||||
int frameCountSum = 0;
|
|
||||||
for (ItemConfig item : itemConfigs) {
|
|
||||||
frameCountSum += item.frameCount;
|
|
||||||
}
|
|
||||||
this.totalExpectedFrameCount = frameCountSum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a {@link Composition} from the sequence configuration.
|
|
||||||
*
|
|
||||||
* <p>{@link Presentation} of {@code width 480, height 360} is used to ensure software encoders
|
|
||||||
* can encode.
|
|
||||||
*/
|
|
||||||
public Composition buildComposition() {
|
|
||||||
ImmutableList.Builder<EditedMediaItem> editedMediaItems = new ImmutableList.Builder<>();
|
|
||||||
for (ItemConfig itemConfig : itemConfigs) {
|
|
||||||
editedMediaItems.add(itemConfig.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Composition.Builder(new EditedMediaItemSequence(editedMediaItems.build()))
|
|
||||||
.setEffects(
|
|
||||||
new Effects(
|
new Effects(
|
||||||
/* audioProcessors= */ ImmutableList.of(),
|
/* audioProcessors= */ ImmutableList.of(),
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
Presentation.createForWidthAndHeight(
|
Presentation.createForWidthAndHeight(
|
||||||
/* width= */ 480, /* height= */ 360, Presentation.LAYOUT_SCALE_TO_FIT))))
|
/* width= */ 480,
|
||||||
.build();
|
/* height= */ 360,
|
||||||
}
|
Presentation.LAYOUT_SCALE_TO_FIT)))));
|
||||||
|
|
||||||
@Override
|
assertThat(result.exportResult.videoFrameCount).isEqualTo(sequence.totalExpectedFrameCount);
|
||||||
public String toString() {
|
assertThat(new File(result.filePath).length()).isGreaterThan(0);
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
stringBuilder.append("Seq{");
|
|
||||||
for (ItemConfig itemConfig : itemConfigs) {
|
|
||||||
stringBuilder.append(itemConfig).append(",");
|
|
||||||
}
|
|
||||||
stringBuilder.replace(stringBuilder.length() - 2, stringBuilder.length(), "}");
|
|
||||||
return stringBuilder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Test parameters for an {@link EditedMediaItem}. */
|
|
||||||
private abstract static class ItemConfig {
|
|
||||||
public final int frameCount;
|
|
||||||
|
|
||||||
private final String uri;
|
|
||||||
@Nullable private final Format format;
|
|
||||||
@Nullable private final Format outputFormat;
|
|
||||||
|
|
||||||
public ItemConfig(
|
|
||||||
String uri, int frameCount, @Nullable Format format, @Nullable Format outputFormat) {
|
|
||||||
this.uri = uri;
|
|
||||||
this.frameCount = frameCount;
|
|
||||||
this.format = format;
|
|
||||||
this.outputFormat = outputFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final EditedMediaItem build() {
|
|
||||||
EditedMediaItem.Builder builder = new EditedMediaItem.Builder(MediaItem.fromUri(uri));
|
|
||||||
onBuild(builder);
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when an {@link EditedMediaItem} is being {@linkplain #build() built}.
|
|
||||||
*
|
|
||||||
* @param builder The {@link EditedMediaItem.Builder} to optionally modify before the item is
|
|
||||||
* built.
|
|
||||||
*/
|
|
||||||
protected abstract void onBuild(EditedMediaItem.Builder builder);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return Iterables.getLast(Splitter.on("/").splitToList(uri));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@link ItemConfig} for an image {@link EditedMediaItem} with a duration of one second. */
|
|
||||||
private static final class ImageItemConfig extends ItemConfig {
|
|
||||||
|
|
||||||
// Image by default are encoded in H265 and BT709 SDR.
|
|
||||||
private static final Format OUTPUT_FORMAT =
|
|
||||||
new Format.Builder()
|
|
||||||
.setSampleMimeType(MimeTypes.VIDEO_H265)
|
|
||||||
.setFrameRate(30.f)
|
|
||||||
.setWidth(480)
|
|
||||||
.setHeight(360)
|
|
||||||
.setColorInfo(ColorInfo.SDR_BT709_LIMITED)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private final long durationUs;
|
|
||||||
private final int frameRate;
|
|
||||||
|
|
||||||
public ImageItemConfig(AssetInfo assetInfo, int frameCount) {
|
|
||||||
this(assetInfo, frameCount, C.MICROS_PER_SECOND);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageItemConfig(AssetInfo assetInfo, int frameRate, long durationUs) {
|
|
||||||
super(
|
|
||||||
assetInfo.uri,
|
|
||||||
/* frameCount= */ (int)
|
|
||||||
Util.scaleLargeValue(
|
|
||||||
frameRate, durationUs, C.MICROS_PER_SECOND, RoundingMode.CEILING),
|
|
||||||
/* format= */ assetInfo.videoFormat,
|
|
||||||
OUTPUT_FORMAT);
|
|
||||||
this.frameRate = frameRate;
|
|
||||||
this.durationUs = durationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBuild(EditedMediaItem.Builder builder) {
|
|
||||||
builder.setFrameRate(frameRate).setDurationUs(durationUs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link ItemConfig} for a video {@link EditedMediaItem}.
|
|
||||||
*
|
|
||||||
* <p>Audio is removed and a {@link Presentation} of specified {@code height=360}.
|
|
||||||
*/
|
|
||||||
private static final class VideoItemConfig extends ItemConfig {
|
|
||||||
public VideoItemConfig(AssetInfo asset) {
|
|
||||||
super(asset.uri, asset.videoFrameCount, asset.videoFormat, asset.videoFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBuild(EditedMediaItem.Builder builder) {
|
|
||||||
builder
|
|
||||||
.setEffects(
|
|
||||||
new Effects(
|
|
||||||
/* audioProcessors= */ ImmutableList.of(),
|
|
||||||
ImmutableList.of(Presentation.createForHeight(360))))
|
|
||||||
.setRemoveAudio(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user