Add sRGB eotf to overlay fragment shader.
The eotf is needed so that overlay (image) colors are correctly interpreted and mixed the linear video colors. Also replaces the 100winners.png with "homemade" image file. Added GlEffectsFrameProcessor test to justify that the color looks correct at the end of frame processing. PiperOrigin-RevId: 506290309
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.effect;
|
||||
|
||||
import static com.google.android.exoplayer2.effect.OverlayTextureProcessorPixelTest.OVERLAY_PNG_ASSET_PATH;
|
||||
import static com.google.android.exoplayer2.testutil.BitmapPixelTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE;
|
||||
import static com.google.android.exoplayer2.testutil.BitmapPixelTestUtil.getBitmapAveragePixelAbsoluteDifferenceArgb8888;
|
||||
import static com.google.android.exoplayer2.testutil.BitmapPixelTestUtil.readBitmap;
|
||||
@ -34,6 +35,7 @@ import com.google.android.exoplayer2.util.Size;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -52,6 +54,9 @@ import org.junit.runner.RunWith;
|
||||
public final class GlEffectsFrameProcessorPixelTest {
|
||||
public static final String ORIGINAL_PNG_ASSET_PATH =
|
||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/original.png";
|
||||
// This file is generated on a Pixel 7, because the emulator isn't able to generate this file.
|
||||
public static final String BITMAP_OVERLAY_PNG_ASSET_PATH =
|
||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_bitmap_FrameProcessor.png";
|
||||
public static final String SCALE_WIDE_PNG_ASSET_PATH =
|
||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/scale_wide.png";
|
||||
public static final String TRANSLATE_RIGHT_PNG_ASSET_PATH =
|
||||
@ -169,6 +174,26 @@ public final class GlEffectsFrameProcessorPixelTest {
|
||||
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("b/267031388 Test can only run on physical devices because emulator cannot produce image")
|
||||
public void bitmapOverlay_matchesGoldenFile() throws Exception {
|
||||
String testId = "bitmapOverlay_matchesGoldenFile";
|
||||
Bitmap overlayBitmap = readBitmap(OVERLAY_PNG_ASSET_PATH);
|
||||
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(overlayBitmap);
|
||||
frameProcessorTestRunner =
|
||||
getDefaultFrameProcessorTestRunnerBuilder(testId)
|
||||
.setEffects(new OverlayEffect(ImmutableList.of(bitmapOverlay)))
|
||||
.build();
|
||||
Bitmap expectedBitmap = readBitmap(BITMAP_OVERLAY_PNG_ASSET_PATH);
|
||||
|
||||
Bitmap actualBitmap = frameProcessorTestRunner.processFirstFrameAndEnd();
|
||||
|
||||
// TODO(b/207848601): switch to using proper tooling for testing against golden data.
|
||||
float averagePixelAbsoluteDifference =
|
||||
getBitmapAveragePixelAbsoluteDifferenceArgb8888(expectedBitmap, actualBitmap, testId);
|
||||
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scaleToFitAndMatrixTransformation_matchesGoldenFile() throws Exception {
|
||||
String testId = "scaleToFitAndMatrixTransformation_matchesGoldenFile";
|
||||
|
@ -58,7 +58,7 @@ import org.junit.runner.RunWith;
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class OverlayTextureProcessorPixelTest {
|
||||
public static final String OVERLAY_PNG_ASSET_PATH = "media/bitmap/overlay/100winners.png";
|
||||
public static final String OVERLAY_PNG_ASSET_PATH = "media/bitmap/overlay/media3test.png";
|
||||
public static final String ORIGINAL_PNG_ASSET_PATH =
|
||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/original.png";
|
||||
public static final String OVERLAY_BITMAP_DEFAULT =
|
||||
@ -132,9 +132,9 @@ public class OverlayTextureProcessorPixelTest {
|
||||
public void drawFrame_bitmapOverlay_blendsBitmapIntoFrame() throws Exception {
|
||||
String testId = "drawFrame_bitmapOverlay";
|
||||
Bitmap overlayBitmap = readBitmap(OVERLAY_PNG_ASSET_PATH);
|
||||
BitmapOverlay scaledBitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(overlayBitmap);
|
||||
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(overlayBitmap);
|
||||
overlayTextureProcessor =
|
||||
new OverlayEffect(ImmutableList.of(scaledBitmapOverlay))
|
||||
new OverlayEffect(ImmutableList.of(bitmapOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
@ -234,6 +234,21 @@ import com.google.common.collect.ImmutableList;
|
||||
.append(" } else {\n")
|
||||
.append(" return clamp(overlayAlpha/videoAlpha, 0.0, 1.0);\n")
|
||||
.append(" }\n")
|
||||
.append("}\n")
|
||||
.append("")
|
||||
.append("float srgbEotfSingleChannel(float srgb) {\n")
|
||||
.append(" return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);\n")
|
||||
.append("}\n")
|
||||
.append("// sRGB EOTF.\n")
|
||||
.append("vec3 applyEotf(const vec3 srgb) {\n")
|
||||
.append("// Reference implementation:\n")
|
||||
.append(
|
||||
"// https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/renderengine/gl/ProgramCache.cpp;drc=de09f10aa504fd8066370591a00c9ff1cafbb7fa;l=235\n")
|
||||
.append(" return vec3(\n")
|
||||
.append(" srgbEotfSingleChannel(srgb.r),\n")
|
||||
.append(" srgbEotfSingleChannel(srgb.g),\n")
|
||||
.append(" srgbEotfSingleChannel(srgb.b)\n")
|
||||
.append(" );\n")
|
||||
.append("}\n");
|
||||
|
||||
for (int texUnitIndex = 1; texUnitIndex <= numOverlays; texUnitIndex++) {
|
||||
@ -253,15 +268,22 @@ import com.google.common.collect.ImmutableList;
|
||||
shader
|
||||
.append(
|
||||
Util.formatInvariant(
|
||||
" vec4 overlayColor%d = getClampToBorderOverlayColor(\n", texUnitIndex))
|
||||
" vec4 electricalOverlayColor%d = getClampToBorderOverlayColor(\n",
|
||||
texUnitIndex))
|
||||
.append(
|
||||
Util.formatInvariant(
|
||||
" uOverlayTexSampler%d, vOverlayTexSamplingCoord%d, uOverlayAlpha%d);\n",
|
||||
texUnitIndex, texUnitIndex, texUnitIndex))
|
||||
.append(Util.formatInvariant(" vec4 opticalOverlayColor%d = vec4(\n", texUnitIndex))
|
||||
.append(
|
||||
Util.formatInvariant(
|
||||
" applyEotf(electricalOverlayColor%d.rgb), electricalOverlayColor%d.a);\n",
|
||||
texUnitIndex, texUnitIndex))
|
||||
.append(" fragColor = mix(\n")
|
||||
.append(
|
||||
Util.formatInvariant(
|
||||
" fragColor, overlayColor%d, getMixAlpha(videoColor.a, overlayColor%d.a));\n",
|
||||
" fragColor, opticalOverlayColor%d, getMixAlpha(videoColor.a,"
|
||||
+ " opticalOverlayColor%d.a));\n",
|
||||
texUnitIndex, texUnitIndex));
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 47 KiB |
BIN
testdata/src/test/assets/media/bitmap/overlay/media3test.png
vendored
Normal file
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 553 KiB |
Before Width: | Height: | Size: 545 KiB After Width: | Height: | Size: 516 KiB |
Before Width: | Height: | Size: 531 KiB After Width: | Height: | Size: 500 KiB |
Before Width: | Height: | Size: 539 KiB After Width: | Height: | Size: 472 KiB |
Before Width: | Height: | Size: 533 KiB After Width: | Height: | Size: 529 KiB |
Before Width: | Height: | Size: 546 KiB After Width: | Height: | Size: 542 KiB |
Before Width: | Height: | Size: 546 KiB After Width: | Height: | Size: 395 KiB |
Before Width: | Height: | Size: 525 KiB After Width: | Height: | Size: 526 KiB |
Before Width: | Height: | Size: 534 KiB After Width: | Height: | Size: 535 KiB |