mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add pixel comparison to FrameExtractorTest
Add PSNR comparison with the output of MedaiMetadataRetriever. PiperOrigin-RevId: 696190585
This commit is contained in:
parent
74611bbdc0
commit
301ef207f2
Binary file not shown.
After Width: | Height: | Size: 303 KiB |
Binary file not shown.
After Width: | Height: | Size: 306 KiB |
Binary file not shown.
After Width: | Height: | Size: 313 KiB |
Binary file not shown.
After Width: | Height: | Size: 332 KiB |
Binary file not shown.
After Width: | Height: | Size: 330 KiB |
@ -17,6 +17,8 @@ package androidx.media3.transformer;
|
||||
|
||||
import static androidx.media3.common.PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND;
|
||||
import static androidx.media3.test.utils.BitmapPixelTestUtil.maybeSaveTestBitmap;
|
||||
import static androidx.media3.test.utils.BitmapPixelTestUtil.readBitmap;
|
||||
import static androidx.media3.test.utils.TestUtil.assertBitmapsAreSimilar;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
@ -33,9 +35,13 @@ import androidx.media3.transformer.ExperimentalFrameExtractor.Frame;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@ -49,9 +55,15 @@ import org.junit.runner.RunWith;
|
||||
/** End-to-end instrumentation test for {@link ExperimentalFrameExtractor}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FrameExtractorTest {
|
||||
// Golden files are generated by MediaMetadataRetriever running on Pixel 8.
|
||||
private static final String GOLDEN_ASSET_FOLDER_PATH =
|
||||
"test-generated-goldens/FrameExtractorTest/";
|
||||
private static final String FILE_PATH =
|
||||
"asset:///media/mp4/sample_with_increasing_timestamps_360p.mp4";
|
||||
private static final long TIMEOUT_SECONDS = 10;
|
||||
// TODO: b/350498258 - Due to bugs in hardware decoders, we can only assert for low PSNR values.
|
||||
// Move to using software decoders in pixel tests, and increase PSNR threshold.
|
||||
private static final float PSNR_THRESHOLD = 25f;
|
||||
|
||||
@Rule public final TestName testName = new TestName();
|
||||
|
||||
@ -77,15 +89,16 @@ public class FrameExtractorTest {
|
||||
frameExtractor = new ExperimentalFrameExtractor(context, MediaItem.fromUri(FILE_PATH));
|
||||
|
||||
ListenableFuture<Frame> frameFuture = frameExtractor.getFrame(/* positionMs= */ 8_500);
|
||||
Bitmap bitmap = frameFuture.get(TIMEOUT_SECONDS, SECONDS).bitmap;
|
||||
Frame frame = frameFuture.get(TIMEOUT_SECONDS, SECONDS);
|
||||
Bitmap actualBitmap = frame.bitmap;
|
||||
Bitmap expectedBitmap =
|
||||
readBitmap(
|
||||
/* assetString= */ GOLDEN_ASSET_FOLDER_PATH
|
||||
+ "sample_with_increasing_timestamps_360p_8.531.png");
|
||||
maybeSaveTestBitmap(testId, /* bitmapLabel= */ "actual", actualBitmap, /* path= */ null);
|
||||
|
||||
maybeSaveTestBitmap(testId, /* bitmapLabel= */ "actual", bitmap, /* path= */ null);
|
||||
assertThat(frameFuture.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(8_531);
|
||||
// TODO: b/350498258 - Actually check Bitmap contents. Due to bugs in hardware decoders,
|
||||
// such a test would require a too high tolerance.
|
||||
assertThat(bitmap.getWidth()).isEqualTo(640);
|
||||
assertThat(bitmap.getHeight()).isEqualTo(360);
|
||||
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888);
|
||||
assertThat(frame.presentationTimeMs).isEqualTo(8_531);
|
||||
assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -93,27 +106,43 @@ public class FrameExtractorTest {
|
||||
frameExtractor = new ExperimentalFrameExtractor(context, MediaItem.fromUri(FILE_PATH));
|
||||
|
||||
ListenableFuture<Frame> frameFuture = frameExtractor.getFrame(/* positionMs= */ 200_000);
|
||||
Frame frame = frameFuture.get(TIMEOUT_SECONDS, SECONDS);
|
||||
Bitmap actualBitmap = frame.bitmap;
|
||||
int lastVideoFramePresentationTimeMs = 17_029;
|
||||
Bitmap expectedBitmap =
|
||||
readBitmap(
|
||||
/* assetString= */ GOLDEN_ASSET_FOLDER_PATH
|
||||
+ "sample_with_increasing_timestamps_360p_17.029.png");
|
||||
maybeSaveTestBitmap(testId, /* bitmapLabel= */ "actual", actualBitmap, /* path= */ null);
|
||||
|
||||
assertThat(frameFuture.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs)
|
||||
.isEqualTo(lastVideoFramePresentationTimeMs);
|
||||
assertThat(frame.presentationTimeMs).isEqualTo(lastVideoFramePresentationTimeMs);
|
||||
assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractFrame_repeatedPositionMs_returnsTheSameFrame() throws Exception {
|
||||
frameExtractor = new ExperimentalFrameExtractor(context, MediaItem.fromUri(FILE_PATH));
|
||||
ImmutableList<Long> requestedFramePositionsMs = ImmutableList.of(0L, 0L, 33L, 34L, 34L);
|
||||
ImmutableList<Long> expectedFramePositionsMs = ImmutableList.of(0L, 0L, 33L, 66L, 66L);
|
||||
List<ListenableFuture<Frame>> frameFutures = new ArrayList<>();
|
||||
|
||||
ListenableFuture<Frame> frame0 = frameExtractor.getFrame(/* positionMs= */ 0);
|
||||
ListenableFuture<Frame> frame0Again = frameExtractor.getFrame(/* positionMs= */ 0);
|
||||
ListenableFuture<Frame> frame33 = frameExtractor.getFrame(/* positionMs= */ 33);
|
||||
ListenableFuture<Frame> frame34 = frameExtractor.getFrame(/* positionMs= */ 34);
|
||||
ListenableFuture<Frame> frame34Again = frameExtractor.getFrame(/* positionMs= */ 34);
|
||||
for (long positionMs : requestedFramePositionsMs) {
|
||||
frameFutures.add(frameExtractor.getFrame(positionMs));
|
||||
}
|
||||
for (int i = 0; i < expectedFramePositionsMs.size(); i++) {
|
||||
ListenableFuture<Frame> frameListenableFuture = frameFutures.get(i);
|
||||
Frame frame = frameListenableFuture.get(TIMEOUT_SECONDS, SECONDS);
|
||||
maybeSaveTestBitmap(testId, /* bitmapLabel= */ "actual_" + i, frame.bitmap, /* path= */ null);
|
||||
Bitmap expectedBitmap =
|
||||
readBitmap(
|
||||
/* assetString= */ GOLDEN_ASSET_FOLDER_PATH
|
||||
+ "sample_with_increasing_timestamps_360p_"
|
||||
+ String.format(Locale.US, "%.3f", frame.presentationTimeMs / 1000f)
|
||||
+ ".png");
|
||||
|
||||
assertThat(frame0.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(0);
|
||||
assertThat(frame0Again.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(0);
|
||||
assertThat(frame33.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(33);
|
||||
assertThat(frame34.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(66);
|
||||
assertThat(frame34Again.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(66);
|
||||
assertBitmapsAreSimilar(expectedBitmap, frame.bitmap, PSNR_THRESHOLD);
|
||||
assertThat(frame.presentationTimeMs).isEqualTo(expectedFramePositionsMs.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user