Skip to content

Commit 41a9a8a

Browse files
committed
test: play real sizes and formats the GPU refuses in the media player
The hardware decoding tests used 320x240 media only, which needs no padding and no cropping, and VP9 4:4:4 was the one stream a decoder refuses. New media: 1080p H.264 with B-frames and 1080p VP9 (decoders put 1080 rows in a surface of 1088 or more, and the player has to crop them), 4K H.264, H.264 at 1366x768 (cropped on the right as well as at the bottom), and H.264 High 10 and High 4:4:4 Predictive, which no hardware decoder takes. Each is one second at 15 fps, 2.7 MB together, made with FFmpeg as the test's comment describes. Hardware and software must give the same pictures at the same size, and the two formats must play on in software without an error. Run on an NVIDIA GeForce RTX 3080 on Windows (Direct3D 11): 20 tests pass with hardware required.
1 parent 6bd0492 commit 41a9a8a

7 files changed

Lines changed: 87 additions & 1 deletion

File tree

‎webrtc-java-media/src/test/java/dev/onvoid/webrtc/media/player/HardwareDecodingTest.java‎

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,30 @@ class HardwareDecodingTest {
8181
/** VP9 profile 1, 4:4:4, which no hardware decoder takes. */
8282
private static final String VP9_444 = "/media-test-vp9-444.webm";
8383

84+
/**
85+
* The larger and odder sizes are one second at 15 fps with a key frame
86+
* every eight frames: 1080p H.264 High with B-frames, 1080p VP9, 4K H.264,
87+
* and H.264 at 1366x768. {@code media-test-h264-10bit.mkv} (High 10) and
88+
* {@code media-test-h264-444.mkv} (High 4:4:4 Predictive) are 320x240, in
89+
* formats no hardware decoder takes. All were made with FFmpeg (libx264 and
90+
* libvpx-vp9) from a moving gradient with a little noise, for example:
91+
* <pre>
92+
* ffmpeg -f lavfi -i "gradients=s=1920x1080:r=15:d=1:speed=0.02,noise=alls=4:allf=t,format=yuv420p" \
93+
* -c:v libx264 -profile:v high -bf 2 -g 8 -crf 30 -maxrate 4M -bufsize 4M -an media-test-h264-1080p.mkv
94+
* </pre>
95+
*/
96+
private static final String H264_1080P = "/media-test-h264-1080p.mkv";
97+
98+
private static final String VP9_1080P = "/media-test-vp9-1080p.webm";
99+
100+
private static final String H264_4K = "/media-test-h264-4k.mkv";
101+
102+
private static final String H264_1366 = "/media-test-h264-1366.mkv";
103+
104+
private static final String H264_10BIT = "/media-test-h264-10bit.mkv";
105+
106+
private static final String H264_444 = "/media-test-h264-444.mkv";
107+
84108
/** VP8, for which no platform has a decoder this module uses. */
85109
private static final String VP8 = "/media-test.webm";
86110

@@ -406,7 +430,62 @@ void decodesConcurrently() throws Exception {
406430
}
407431
}
408432

433+
@Test
434+
void h264MatchesSoftware1080p() throws Exception {
435+
// 1080 rows are not a multiple of the 16 of a macroblock: the decoder
436+
// puts them in a surface of 1088 and the player has to crop it.
437+
assertMatchesSoftware(H264_1080P, 15, "1920x1080");
438+
}
439+
440+
@Test
441+
void vp9MatchesSoftware1080p() throws Exception {
442+
// VP9 decodes in blocks of 64, so the surface is larger still.
443+
assertMatchesSoftware(VP9_1080P, 15, "1920x1080");
444+
}
445+
446+
@Test
447+
void h264MatchesSoftware4k() throws Exception {
448+
assertMatchesSoftware(H264_4K, 15, "3840x2160");
449+
}
450+
451+
@Test
452+
void h264MatchesSoftwareLaptopSize() throws Exception {
453+
// 1366x768: a width that is no multiple of 16 and not of 8 either, so
454+
// the picture is cropped on the right as well as at the bottom.
455+
assertMatchesSoftware(H264_1366, 15, "1366x768");
456+
}
457+
458+
@Test
459+
void tenBitH264FallsBack() throws Exception {
460+
assertFallsBack(H264_10BIT);
461+
}
462+
463+
@Test
464+
void h264444FallsBack() throws Exception {
465+
assertFallsBack(H264_444);
466+
}
467+
468+
/**
469+
* A stream that hardware decoders do not take is played in software, with
470+
* the pictures software decoding gives and no error.
471+
*/
472+
private void assertFallsBack(String asset) throws Exception {
473+
Result software = play(asset, false, 0);
474+
Result hardware = play(asset, true, 0);
475+
476+
assertNull(software.error);
477+
assertNull(hardware.error);
478+
479+
assertFalse(hardware.hardware);
480+
assertEquals(15, hardware.frames.size());
481+
assertEquals(software.frames, hardware.frames);
482+
}
483+
409484
private void assertMatchesSoftware(String asset) throws Exception {
485+
assertMatchesSoftware(asset, FRAMES, null);
486+
}
487+
488+
private void assertMatchesSoftware(String asset, int frames, String size) throws Exception {
410489
Result software = play(asset, false, 0);
411490
Result hardware = play(asset, true, 0);
412491

@@ -415,7 +494,12 @@ private void assertMatchesSoftware(String asset) throws Exception {
415494

416495
requireHardware(hardware);
417496

418-
assertEquals(FRAMES, software.frames.size());
497+
assertEquals(frames, software.frames.size());
498+
499+
if (size != null) {
500+
assertEquals(size, software.size);
501+
assertEquals(size, hardware.size);
502+
}
419503

420504
// The pictures are the same, frame by frame.
421505
assertEquals(software.frames, hardware.frames);
@@ -450,6 +534,7 @@ private Result play(String asset, boolean hardware, long positionUs) throws Exce
450534
CustomVideoSource source = new CustomVideoSource();
451535
VideoTrack track = factory.createVideoTrack("video", source);
452536
VideoTrackSink sink = frame -> {
537+
result.size = frame.buffer.getWidth() + "x" + frame.buffer.getHeight();
453538
result.frames.add(lumaChecksum(frame.buffer.toI420()));
454539

455540
frame.release();
@@ -570,6 +655,7 @@ private static final class Result {
570655
final List<Long> frames = Collections.synchronizedList(new ArrayList<>());
571656
volatile String error;
572657
volatile boolean hardware;
658+
volatile String size;
573659

574660
}
575661

574 KB
Binary file not shown.
27.8 KB
Binary file not shown.
382 KB
Binary file not shown.
124 KB
Binary file not shown.
97.8 KB
Binary file not shown.
1.36 MB
Binary file not shown.

0 commit comments

Comments
 (0)