Support upscaling with LanczosResample

Avoid scaling the lanczos windown function when scaling up.
When scaling up (output > input), we shouldn't scale the window
function or we risk not sampling any of the input pixels.

PiperOrigin-RevId: 641838149
This commit is contained in:
dancho 2024-06-10 02:58:27 -07:00 committed by Copybara-Service
parent 228d63848e
commit abf601feaa
3 changed files with 42 additions and 17 deletions

View File

@ -53,8 +53,11 @@ public class LanczosResampleTest {
@Rule public final TestName testName = new TestName();
private static final String ORIGINAL_JPG_ASSET_PATH = "media/jpeg/ultraHDR.jpg";
private static final String SMALLER_JPG_ASSET_PATH = "media/jpeg/london.jpg";
private static final String DOWNSCALED_6X_PNG_ASSET_PATH =
"test-generated-goldens/LanczosResampleTest/ultraHDR_512x680.png";
private static final String UPSCALED_3X_PNG_ASSET_PATH =
"test-generated-goldens/LanczosResampleTest/london_3060x2304.jpg";
private final Context context = getApplicationContext();
@ -63,20 +66,12 @@ public class LanczosResampleTest {
private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull EGLSurface placeholderEglSurface;
private @MonotonicNonNull GlShaderProgram lanczosShaderProgram;
private int inputTexId;
private int inputWidth;
private int inputHeight;
@Before
public void createGlObjects() throws Exception {
eglDisplay = GlUtil.getDefaultEglDisplay();
eglContext = GlUtil.createEglContext(eglDisplay);
placeholderEglSurface = GlUtil.createFocusedPlaceholderEglSurface(eglContext, eglDisplay);
Bitmap inputBitmap = readBitmap(ORIGINAL_JPG_ASSET_PATH);
inputWidth = inputBitmap.getWidth();
inputHeight = inputBitmap.getHeight();
inputTexId = createGlTextureFromBitmap(inputBitmap);
}
@Before
@ -94,20 +89,15 @@ public class LanczosResampleTest {
@Test
public void queueInputFrame_with6xDownscale_matchesGoldenFile() throws Exception {
GlTextureInfo inputTextureInfo = setupInputTexture(ORIGINAL_JPG_ASSET_PATH);
float scale = 1f / 6;
Size outputSize = new Size((int) (inputWidth * scale), (int) (inputHeight * scale));
Size outputSize =
new Size((int) (inputTextureInfo.width * scale), (int) (inputTextureInfo.height * scale));
lanczosShaderProgram =
LanczosResample.scaleToFit(outputSize.getWidth(), outputSize.getHeight())
.toGlShaderProgram(context, /* useHdr= */ false);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(DOWNSCALED_6X_PNG_ASSET_PATH);
GlTextureInfo inputTextureInfo =
new GlTextureInfo(
inputTexId,
/* fboId= */ C.INDEX_UNSET,
/* rboId= */ C.INDEX_UNSET,
inputWidth,
inputHeight);
lanczosShaderProgram.queueInputFrame(
new DefaultGlObjectsProvider(eglContext), inputTextureInfo, /* presentationTimeUs= */ 0);
@ -118,6 +108,37 @@ public class LanczosResampleTest {
assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD);
}
@Test
public void queueInputFrame_with3xUpscale_matchesGoldenFile() throws Exception {
GlTextureInfo inputTextureInfo = setupInputTexture(SMALLER_JPG_ASSET_PATH);
float scale = 3;
Size outputSize =
new Size((int) (inputTextureInfo.width * scale), (int) (inputTextureInfo.height * scale));
lanczosShaderProgram =
LanczosResample.scaleToFit(outputSize.getWidth(), outputSize.getHeight())
.toGlShaderProgram(context, /* useHdr= */ false);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(UPSCALED_3X_PNG_ASSET_PATH);
lanczosShaderProgram.queueInputFrame(
new DefaultGlObjectsProvider(eglContext), inputTextureInfo, /* presentationTimeUs= */ 0);
Bitmap actualBitmap =
createArgb8888BitmapFromFocusedGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
maybeSaveTestBitmap(testId, /* bitmapLabel= */ "actual", actualBitmap, /* path= */ null);
assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD);
}
private static GlTextureInfo setupInputTexture(String path) throws Exception {
Bitmap inputBitmap = readBitmap(path);
return new GlTextureInfo(
createGlTextureFromBitmap(inputBitmap),
/* fboId= */ C.INDEX_UNSET,
/* rboId= */ C.INDEX_UNSET,
inputBitmap.getWidth(),
inputBitmap.getHeight());
}
private void setupOutputTexture(int outputWidth, int outputHeight) throws Exception {
int outputTexId =
GlUtil.createTexture(

View File

@ -16,6 +16,7 @@
package androidx.media3.effect;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.Math.min;
import static java.lang.Math.round;
import android.content.Context;
@ -92,7 +93,10 @@ public final class LanczosResample implements GlEffect {
@Override
public ConvolutionFunction1D getConvolution(long presentationTimeUs) {
return new ScaledLanczosFunction(radius, scale);
// When scaling down (scale < 1), scale the kernel function to ensure we sample all input
// pixels inside the kernel radius.
// When scaling up (scale > 1), leave the kernel function unchanged.
return new ScaledLanczosFunction(radius, min(scale, 1f));
}
@Override

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB