Use inputFormat.tileCountHorizontal to calculate tileStartXCoordinate for cropping the correct tile from outputBitmap

To find the column of an index in a matrix the formula "column = index % width" should be used, not "column = index % height"

If inputFormat.tileCountVertical was equal to 1 then it would not throw an error, but instead result in the first tile of the bitmap always being returned. If inputFormat.tileCountVertical was larger than 1 then Bitmap.createBitmap() would throw an error as it would attempt to go outside the bounds of outputBitmap

ImageRenderTest has been updated to test for 2x3 images so that tileCountVertical != tileCountHorizontal. These tests passed previously because they were equal, so using tileCountVertical produced the same results as tileCountHorizontal
This commit is contained in:
Håkon Schia 2024-04-20 08:16:43 +02:00 committed by microkatz
parent feb512544a
commit 9ced27a030
2 changed files with 71 additions and 41 deletions

View File

@ -571,7 +571,7 @@ public class ImageRenderer extends BaseRenderer {
checkStateNotNull(outputBitmap);
int tileWidth = outputBitmap.getWidth() / checkStateNotNull(inputFormat).tileCountHorizontal;
int tileHeight = outputBitmap.getHeight() / checkStateNotNull(inputFormat).tileCountVertical;
int tileStartXCoordinate = tileWidth * (tileIndex % inputFormat.tileCountVertical);
int tileStartXCoordinate = tileWidth * (tileIndex % inputFormat.tileCountHorizontal);
int tileStartYCoordinate = tileHeight * (tileIndex / inputFormat.tileCountHorizontal);
return Bitmap.createBitmap(
outputBitmap, tileStartXCoordinate, tileStartYCoordinate, tileWidth, tileHeight);

View File

@ -66,16 +66,16 @@ public class ImageRendererTest {
.setTileCountVertical(1)
.setTileCountHorizontal(1)
.build();
private static final Format JPEG_FORMAT_WITH_FOUR_TILES =
private static final Format JPEG_FORMAT_WITH_SIX_TILES =
new Format.Builder()
.setSampleMimeType(MimeTypes.IMAGE_JPEG)
.setTileCountVertical(2)
.setTileCountVertical(3)
.setTileCountHorizontal(2)
.build();
private final List<Pair<Long, Bitmap>> renderedBitmaps = new ArrayList<>();
private final Bitmap fakeDecodedBitmap1 =
Bitmap.createBitmap(/* width= */ 2, /* height= */ 2, Bitmap.Config.ARGB_8888);
Bitmap.createBitmap(/* width= */ 2, /* height= */ 3, Bitmap.Config.ARGB_8888);
private final Bitmap fakeDecodedBitmap2 =
Bitmap.createBitmap(/* width= */ 4, /* height= */ 4, Bitmap.Config.ARGB_8888);
@ -223,16 +223,18 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream1 =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0)));
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0)));
fakeSampleStream1.writeData(/* startPositionUs= */ 0);
FakeSampleStream fakeSampleStream2 =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 10L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
END_OF_STREAM_ITEM));
@ -254,25 +256,27 @@ public class ImageRendererTest {
renderer.start();
renderer.render(/* positionUs= */ 200_000L, /* elapsedRealtimeUs= */ 0);
renderer.render(/* positionUs= */ 300_000L, /* elapsedRealtimeUs= */ 0);
renderer.render(/* positionUs= */ 400_000L, /* elapsedRealtimeUs= */ 0);
renderer.render(/* positionUs= */ 500_000L, /* elapsedRealtimeUs= */ 0);
renderer.replaceStream(
new Format[] {PNG_FORMAT},
fakeSampleStream2,
/* startPositionUs= */ 10,
/* offsetUs= */ 450_000L,
/* offsetUs= */ 650_000L,
new MediaSource.MediaPeriodId(new Object()));
renderer.setCurrentStreamFinal();
// Render last sample of first stream
renderer.render(/* positionUs= */ 400_000L, /* elapsedRealtimeUs= */ 0);
renderer.render(/* positionUs= */ 600_000L, /* elapsedRealtimeUs= */ 0);
StopWatch hasReadStreamToEndStopWatch = new StopWatch(HAS_READ_STREAM_TO_END_TIMEOUT_MESSAGE);
while (!renderer.hasReadStreamToEnd() && hasReadStreamToEndStopWatch.ensureNotExpired()) {
renderer.render(/* positionUs= */ 450_010L, /* elapsedRealtimeUs= */ 0L);
renderer.render(/* positionUs= */ 650_010L, /* elapsedRealtimeUs= */ 0L);
}
renderer.stop();
assertThat(renderedBitmaps).hasSize(5);
assertThat(renderedBitmaps).hasSize(7);
assertThat(renderedBitmaps.get(0).first).isEqualTo(0);
assertThat(renderedBitmaps.get(4).first).isEqualTo(10L);
assertThat(renderedBitmaps.get(6).first).isEqualTo(10L);
}
@Test
@ -280,7 +284,7 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream1 =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
@ -289,7 +293,7 @@ public class ImageRendererTest {
fakeSampleStream1.writeData(/* startPositionUs= */ 0);
FakeSampleStream fakeSampleStream2 =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 10L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
END_OF_STREAM_ITEM));
@ -397,17 +401,19 @@ public class ImageRendererTest {
public void render_tiledImage_cropsAndRendersToImageOutput() throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
@ -431,7 +437,7 @@ public class ImageRendererTest {
positionUs += 100_000;
}
assertThat(renderedBitmaps).hasSize(4);
assertThat(renderedBitmaps).hasSize(6);
assertThat(renderedBitmaps.get(0).first).isEqualTo(0L);
assertThat(renderedBitmaps.get(0).second.getHeight()).isEqualTo(1);
assertThat(renderedBitmaps.get(0).second.getWidth()).isEqualTo(1);
@ -444,23 +450,31 @@ public class ImageRendererTest {
assertThat(renderedBitmaps.get(3).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(3).second.getHeight()).isEqualTo(1);
assertThat(renderedBitmaps.get(3).second.getWidth()).isEqualTo(1);
assertThat(renderedBitmaps.get(4).first).isEqualTo(400_000L);
assertThat(renderedBitmaps.get(4).second.getHeight()).isEqualTo(1);
assertThat(renderedBitmaps.get(4).second.getWidth()).isEqualTo(1);
assertThat(renderedBitmaps.get(5).first).isEqualTo(500_000L);
assertThat(renderedBitmaps.get(5).second.getHeight()).isEqualTo(1);
assertThat(renderedBitmaps.get(5).second.getWidth()).isEqualTo(1);
}
@Test
public void render_tiledImageWithNonZeroStartPosition_rendersToImageOutput() throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 200_000,
/* joining= */ false,
@ -484,9 +498,11 @@ public class ImageRendererTest {
positionUs += 100_000;
}
assertThat(renderedBitmaps).hasSize(2);
assertThat(renderedBitmaps).hasSize(4);
assertThat(renderedBitmaps.get(0).first).isEqualTo(200_000L);
assertThat(renderedBitmaps.get(1).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(2).first).isEqualTo(400_000L);
assertThat(renderedBitmaps.get(3).first).isEqualTo(500_000L);
}
@Test
@ -494,17 +510,19 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
@ -517,11 +535,11 @@ public class ImageRendererTest {
StopWatch isReadyStopWatch = new StopWatch(IS_READY_TIMEOUT_MESSAGE);
while (!renderer.isReady() && isReadyStopWatch.ensureNotExpired()) {
renderer.render(
/* positionUs= */ 350_000,
/* positionUs= */ 550_000,
/* elapsedRealtimeUs= */ SystemClock.DEFAULT.elapsedRealtime() * 1000);
}
StopWatch isEndedStopWatch = new StopWatch(IS_ENDED_TIMEOUT_MESSAGE);
long positionUs = 350_000;
long positionUs = 550_000;
while (!renderer.isEnded() && isEndedStopWatch.ensureNotExpired()) {
renderer.render(
positionUs, /* elapsedRealtimeUs= */ SystemClock.DEFAULT.elapsedRealtime() * 1000);
@ -529,7 +547,7 @@ public class ImageRendererTest {
}
assertThat(renderedBitmaps).hasSize(1);
assertThat(renderedBitmaps.get(0).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(0).first).isEqualTo(500_000L);
}
@Test
@ -537,17 +555,19 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
@ -560,11 +580,11 @@ public class ImageRendererTest {
StopWatch isReadyStopWatch = new StopWatch(IS_READY_TIMEOUT_MESSAGE);
while (!renderer.isReady() && isReadyStopWatch.ensureNotExpired()) {
renderer.render(
/* positionUs= */ 250_000L,
/* positionUs= */ 450_000L,
/* elapsedRealtimeUs= */ SystemClock.DEFAULT.elapsedRealtime() * 1000);
}
StopWatch isEndedStopWatch = new StopWatch(IS_ENDED_TIMEOUT_MESSAGE);
long positionUs = 250_000L;
long positionUs = 450_000L;
while (!renderer.isEnded() && isEndedStopWatch.ensureNotExpired()) {
renderer.render(
positionUs, /* elapsedRealtimeUs= */ SystemClock.DEFAULT.elapsedRealtime() * 1000);
@ -572,8 +592,8 @@ public class ImageRendererTest {
}
assertThat(renderedBitmaps).hasSize(2);
assertThat(renderedBitmaps.get(0).first).isEqualTo(200_000L);
assertThat(renderedBitmaps.get(1).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(0).first).isEqualTo(400_000L);
assertThat(renderedBitmaps.get(1).first).isEqualTo(500_000L);
}
@Test
@ -582,17 +602,19 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
@ -616,10 +638,12 @@ public class ImageRendererTest {
positionUs += 100_000;
}
assertThat(renderedBitmaps).hasSize(3);
assertThat(renderedBitmaps).hasSize(5);
assertThat(renderedBitmaps.get(0).first).isEqualTo(100_000L);
assertThat(renderedBitmaps.get(1).first).isEqualTo(200_000L);
assertThat(renderedBitmaps.get(2).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(3).first).isEqualTo(400_000L);
assertThat(renderedBitmaps.get(4).first).isEqualTo(500_000L);
}
@Test
@ -628,17 +652,19 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
@ -662,10 +688,12 @@ public class ImageRendererTest {
positionUs += 100_000;
}
assertThat(renderedBitmaps).hasSize(3);
assertThat(renderedBitmaps).hasSize(5);
assertThat(renderedBitmaps.get(0).first).isEqualTo(100_000L);
assertThat(renderedBitmaps.get(1).first).isEqualTo(200_000L);
assertThat(renderedBitmaps.get(2).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(3).first).isEqualTo(400_000L);
assertThat(renderedBitmaps.get(4).first).isEqualTo(500_000L);
}
@Test
@ -673,17 +701,19 @@ public class ImageRendererTest {
throws Exception {
FakeSampleStream fakeSampleStream =
createSampleStream(
JPEG_FORMAT_WITH_FOUR_TILES,
JPEG_FORMAT_WITH_SIX_TILES,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0L, /* flags= */ C.BUFFER_FLAG_KEY_FRAME),
emptySample(/* timeUs= */ 100_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 200_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 300_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 400_000L, /* flags= */ 0),
emptySample(/* timeUs= */ 500_000L, /* flags= */ 0),
END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
renderer.enable(
RendererConfiguration.DEFAULT,
new Format[] {JPEG_FORMAT_WITH_FOUR_TILES},
new Format[] {JPEG_FORMAT_WITH_SIX_TILES},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
@ -696,7 +726,7 @@ public class ImageRendererTest {
StopWatch isReadyStopWatch = new StopWatch(IS_READY_TIMEOUT_MESSAGE);
while (!renderer.isReady() && isReadyStopWatch.ensureNotExpired()) {
renderer.render(
/* positionUs= */ 330_000,
/* positionUs= */ 530_000,
/* elapsedRealtimeUs= */ SystemClock.DEFAULT.elapsedRealtime() * 1000);
}
StopWatch isEndedStopWatch = new StopWatch(IS_ENDED_TIMEOUT_MESSAGE);
@ -708,7 +738,7 @@ public class ImageRendererTest {
}
assertThat(renderedBitmaps).hasSize(1);
assertThat(renderedBitmaps.get(0).first).isEqualTo(300_000L);
assertThat(renderedBitmaps.get(0).first).isEqualTo(500_000L);
}
private static FakeSampleStream.FakeSampleStreamItem emptySample(