diff --git a/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java b/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java index 67605237c0..070bcbd7c2 100644 --- a/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java +++ b/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java @@ -39,6 +39,7 @@ import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.transformer.ProgressHolder; import com.google.android.exoplayer2.transformer.TransformationException; import com.google.android.exoplayer2.transformer.TransformationRequest; +import com.google.android.exoplayer2.transformer.TransformationResult; import com.google.android.exoplayer2.transformer.Transformer; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.ui.StyledPlayerView; @@ -223,7 +224,8 @@ public final class TransformerActivity extends AppCompatActivity { .addListener( new Transformer.Listener() { @Override - public void onTransformationCompleted(MediaItem mediaItem) { + public void onTransformationCompleted( + MediaItem mediaItem, TransformationResult transformationResult) { TransformerActivity.this.onTransformationCompleted(filePath); } diff --git a/docs/transforming-media.md b/docs/transforming-media.md index 81f54a8656..4ad82abeb4 100644 --- a/docs/transforming-media.md +++ b/docs/transforming-media.md @@ -65,7 +65,7 @@ app is notified of events via the listener passed to the `Transformer` builder. Transformer.Listener transformerListener = new Transformer.Listener() { @Override - public void onTransformationCompleted(MediaItem inputMediaItem) { + public void onTransformationCompleted(MediaItem inputMediaItem, TransformationResult transformationResult) { playOutput(); } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/C.java b/library/common/src/main/java/com/google/android/exoplayer2/C.java index c41273d57d..a8d37d0912 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/C.java @@ -69,6 +69,9 @@ public final class C { /** Represents an unset or unknown rate. */ public static final float RATE_UNSET = -Float.MAX_VALUE; + /** Represents an unset or unknown integer rate. */ + public static final int RATE_UNSET_INT = Integer.MIN_VALUE + 1; + /** Represents an unset or unknown length. */ public static final int LENGTH_UNSET = -1; diff --git a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java index 286d959d1c..56172633bc 100644 --- a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java +++ b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java @@ -24,6 +24,7 @@ import android.net.Uri; import android.os.Build; import androidx.annotation.Nullable; import androidx.test.platform.app.InstrumentationRegistry; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.MediaItem; import java.io.File; import java.io.FileWriter; @@ -39,50 +40,6 @@ public final class AndroidTestUtil { public static final String REMOTE_MP4_10_SECONDS_URI_STRING = "https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4"; - /** Information about the result of successfully running a transformer. */ - public static final class TransformationResult { - - /** A builder for {@link TransformationResult} instances. */ - public static final class Builder { - private final String testId; - @Nullable private Long fileSizeBytes; - - public Builder(String testId) { - this.testId = testId; - } - - public Builder setFileSizeBytes(long fileSizeBytes) { - this.fileSizeBytes = fileSizeBytes; - return this; - } - - public TransformationResult build() { - return new TransformationResult(testId, fileSizeBytes); - } - } - - public final String testId; - @Nullable public final Long fileSizeBytes; - - private TransformationResult(String testId, @Nullable Long fileSizeBytes) { - this.testId = testId; - this.fileSizeBytes = fileSizeBytes; - } - - /** - * Returns all the analysis data from the test. - * - *
If a value was not generated, it will not be part of the return value.
- */
- public String getFormattedAnalysis() {
- String analysis = "test=" + testId;
- if (fileSizeBytes != null) {
- analysis += ", fileSizeBytes=" + fileSizeBytes;
- }
- return analysis;
- }
- }
-
/**
* Transforms the {@code uriString} with the {@link Transformer}.
*
@@ -98,6 +55,7 @@ public final class AndroidTestUtil {
Context context, String testId, Transformer transformer, String uriString, int timeoutSeconds)
throws Exception {
AtomicReference<@NullableType Exception> exceptionReference = new AtomicReference<>();
+ AtomicReference Input must be positive or {@link C#LENGTH_UNSET}.
+ */
+ public Builder setFileSizeBytes(long fileSizeBytes) {
+ checkArgument(fileSizeBytes > 0 || fileSizeBytes == C.LENGTH_UNSET);
+ this.fileSizeBytes = fileSizeBytes;
+ return this;
+ }
+
+ /**
+ * Sets the average audio bitrate.
+ *
+ * Input must be positive or {@link C#RATE_UNSET_INT}.
+ */
+ public Builder setAverageAudioBitrate(int averageAudioBitrate) {
+ checkArgument(averageAudioBitrate > 0 || averageAudioBitrate == C.RATE_UNSET_INT);
+ this.averageAudioBitrate = averageAudioBitrate;
+ return this;
+ }
+
+ /**
+ * Sets the average video bitrate.
+ *
+ * Input must be positive or {@link C#RATE_UNSET_INT}.
+ */
+ public Builder setAverageVideoBitrate(int averageVideoBitrate) {
+ checkArgument(averageVideoBitrate > 0 || averageVideoBitrate == C.RATE_UNSET_INT);
+ this.averageVideoBitrate = averageVideoBitrate;
+ return this;
+ }
+
+ public TransformationResult build() {
+ return new TransformationResult(fileSizeBytes, averageAudioBitrate, averageVideoBitrate);
+ }
+ }
+
+ /** The size of the file in bytes, or {@link C#LENGTH_UNSET} if unset or unknown. */
+ public final long fileSizeBytes;
+ /**
+ * The average bitrate of the audio track data, or {@link C#RATE_UNSET_INT} if unset or unknown.
+ */
+ public final int averageAudioBitrate;
+ /**
+ * The average bitrate of the video track data, or {@link C#RATE_UNSET_INT} if unset or unknown.
+ */
+ public final int averageVideoBitrate;
+
+ private TransformationResult(
+ long fileSizeBytes, int averageAudioBitrate, int averageVideoBitrate) {
+ this.fileSizeBytes = fileSizeBytes;
+ this.averageAudioBitrate = averageAudioBitrate;
+ this.averageVideoBitrate = averageVideoBitrate;
+ }
+
+ public Builder buildUpon() {
+ return new Builder()
+ .setFileSizeBytes(fileSizeBytes)
+ .setAverageAudioBitrate(averageAudioBitrate)
+ .setAverageVideoBitrate(averageVideoBitrate);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof TransformationResult)) {
+ return false;
+ }
+ TransformationResult result = (TransformationResult) o;
+ return fileSizeBytes == result.fileSizeBytes
+ && averageAudioBitrate == result.averageAudioBitrate
+ && averageVideoBitrate == result.averageVideoBitrate;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) fileSizeBytes;
+ result = 31 * result + averageAudioBitrate;
+ result = 31 * result + averageVideoBitrate;
+ return result;
+ }
+}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
index 826d6b8226..2a3055bcf2 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
@@ -443,12 +443,22 @@ public final class Transformer {
/** A listener for the transformation events. */
public interface Listener {
+ /**
+ * @deprecated Use {@link #onTransformationCompleted(MediaItem, TransformationResult)} instead.
+ */
+ @Deprecated
+ default void onTransformationCompleted(MediaItem inputMediaItem) {}
+
/**
* Called when the transformation is completed successfully.
*
* @param inputMediaItem The {@link MediaItem} for which the transformation is completed.
+ * @param transformationResult The {@link TransformationResult} of the transformation.
*/
- default void onTransformationCompleted(MediaItem inputMediaItem) {}
+ default void onTransformationCompleted(
+ MediaItem inputMediaItem, TransformationResult transformationResult) {
+ onTransformationCompleted(inputMediaItem);
+ }
/** @deprecated Use {@link #onTransformationError(MediaItem, TransformationException)}. */
@Deprecated
@@ -733,8 +743,9 @@ public final class Transformer {
* Returns the current {@link ProgressState} and updates {@code progressHolder} with the current
* progress if it is {@link #PROGRESS_STATE_AVAILABLE available}.
*
- * After a transformation {@link Listener#onTransformationCompleted(MediaItem) completes}, this
- * method returns {@link #PROGRESS_STATE_NO_TRANSFORMATION}.
+ * After a transformation {@link Listener#onTransformationCompleted(MediaItem,
+ * TransformationResult) completes}, this method returns {@link
+ * #PROGRESS_STATE_NO_TRANSFORMATION}.
*
* @param progressHolder A {@link ProgressHolder}, updated to hold the percentage progress if
* {@link #PROGRESS_STATE_AVAILABLE available}.
@@ -950,9 +961,14 @@ public final class Transformer {
/* eventFlag= */ C.INDEX_UNSET,
listener -> listener.onTransformationError(mediaItem, finalException));
} else {
+ TransformationResult result =
+ new TransformationResult.Builder()
+ .setAverageAudioBitrate(muxerWrapper.getTrackAverageBitrate(C.TRACK_TYPE_AUDIO))
+ .setAverageVideoBitrate(muxerWrapper.getTrackAverageBitrate(C.TRACK_TYPE_VIDEO))
+ .build();
listeners.queueEvent(
/* eventFlag= */ C.INDEX_UNSET,
- listener -> listener.onTransformationCompleted(mediaItem));
+ listener -> listener.onTransformationCompleted(mediaItem, result));
}
listeners.flushEvents();
}
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java
index 8b9ad9b4e3..d1148f28dc 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java
@@ -22,6 +22,8 @@ import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STA
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_WAITING_FOR_AVAILABILITY;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -57,6 +59,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -239,9 +242,9 @@ public final class TransformerEndToEndTest {
transformer.startTransformation(mediaItem, outputPath);
TransformerTestRunner.runUntilCompleted(transformer);
- verify(mockListener1, times(1)).onTransformationCompleted(mediaItem);
- verify(mockListener2, times(1)).onTransformationCompleted(mediaItem);
- verify(mockListener3, times(1)).onTransformationCompleted(mediaItem);
+ verify(mockListener1, times(1)).onTransformationCompleted(eq(mediaItem), any());
+ verify(mockListener2, times(1)).onTransformationCompleted(eq(mediaItem), any());
+ verify(mockListener3, times(1)).onTransformationCompleted(eq(mediaItem), any());
}
@Test
@@ -313,9 +316,9 @@ public final class TransformerEndToEndTest {
transformer2.startTransformation(mediaItem, outputPath);
TransformerTestRunner.runUntilCompleted(transformer2);
- verify(mockListener1, times(1)).onTransformationCompleted(mediaItem);
- verify(mockListener2, never()).onTransformationCompleted(mediaItem);
- verify(mockListener3, times(1)).onTransformationCompleted(mediaItem);
+ verify(mockListener1, times(1)).onTransformationCompleted(eq(mediaItem), any());
+ verify(mockListener2, never()).onTransformationCompleted(eq(mediaItem), any());
+ verify(mockListener3, times(1)).onTransformationCompleted(eq(mediaItem), any());
}
@Test
@@ -333,6 +336,30 @@ public final class TransformerEndToEndTest {
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SEF_SLOW_MOTION));
}
+ @Test
+ public void startTransformation_completesWithValidBitrate() throws Exception {
+ AtomicReference<@NullableType TransformationResult> resultReference = new AtomicReference<>();
+ Transformer.Listener listener =
+ new Transformer.Listener() {
+ @Override
+ public void onTransformationCompleted(
+ MediaItem inputMediaItem, TransformationResult transformationResult) {
+ resultReference.set(transformationResult);
+ }
+ };
+ Transformer transformer =
+ createTransformerBuilder(/* disableFallback= */ true).addListener(listener).build();
+ MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
+
+ transformer.startTransformation(mediaItem, outputPath);
+ TransformerTestRunner.runUntilCompleted(transformer);
+
+ @Nullable TransformationResult result = resultReference.get();
+ assertThat(result).isNotNull();
+ assertThat(result.averageAudioBitrate).isGreaterThan(0);
+ assertThat(result.averageVideoBitrate).isGreaterThan(0);
+ }
+
@Test
public void startTransformation_withAudioEncoderFormatUnsupported_completesWithError()
throws Exception {
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTestRunner.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTestRunner.java
index 1e837be970..86e2853c8d 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTestRunner.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTestRunner.java
@@ -78,7 +78,8 @@ public final class TransformerTestRunner {
transformer.addListener(
new Transformer.Listener() {
@Override
- public void onTransformationCompleted(MediaItem inputMediaItem) {
+ public void onTransformationCompleted(
+ MediaItem inputMediaItem, TransformationResult transformationResult) {
transformationCompleted.set(true);
}