Fix output pixel aspect ratio and add test for it

This commit is contained in:
Daniele Sparano 2024-08-28 12:37:11 +01:00 committed by microkatz
parent f0463bff8a
commit 7473156853
2 changed files with 92 additions and 3 deletions

View File

@ -1342,10 +1342,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
? mediaFormat.getInteger(KEY_CROP_BOTTOM) - mediaFormat.getInteger(KEY_CROP_TOP) + 1
: mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
}
boolean hasPixelAspectRatio = mediaFormat.containsKey(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH)
boolean hasPixelAspectRatio = (Util.SDK_INT >= 30) && mediaFormat != null && mediaFormat.containsKey(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH)
&& mediaFormat.containsKey(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT);
pixelWidthHeightRatio = hasPixelAspectRatio ?
mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH) /
(float)mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH) /
mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT)
: format.pixelWidthHeightRatio;
// The decoder applies the rotation when rendering to the surface. For 90 and 270 degree

View File

@ -50,6 +50,7 @@ import androidx.media3.common.MimeTypes;
import androidx.media3.common.TrackGroup;
import androidx.media3.common.VideoSize;
import androidx.media3.common.util.Clock;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.CryptoInfo;
import androidx.media3.exoplayer.DecoderCounters;
import androidx.media3.exoplayer.ExoPlaybackException;
@ -100,6 +101,7 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowDisplay;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.shadows.ShadowSystemClock;
@ -747,6 +749,71 @@ public class MediaCodecVideoRendererTest {
new VideoSize(VIDEO_H264.width, VIDEO_H264.height, VIDEO_H264.pixelWidthHeightRatio));
}
@Config(minSdk = 30)
@Test
public void render_withMediaCodecAlteringPixelAspectRatioWidthHeight_sendsVideoSizeChangeWithMediaFormatValues() throws Exception {
MediaCodecAdapter.Factory codecAdapterFactory =
configuration ->
new ForwardingSynchronousMediaCodecAdapterAlteringPixelAspectRatio(
new SynchronousMediaCodecAdapter.Factory().createAdapter(configuration));
MediaCodecVideoRenderer mediaCodecVideoRendererWithCustomAdapter =
new MediaCodecVideoRenderer(
ApplicationProvider.getApplicationContext(),
codecAdapterFactory,
mediaCodecSelector,
/* allowedJoiningTimeMs= */ 0,
/* enableDecoderFallback= */ false,
/* eventHandler= */ new Handler(testMainLooper),
/* eventListener= */ eventListener,
/* maxDroppedFramesToNotify= */ 1) {
@Override
protected @Capabilities int supportsFormat(
MediaCodecSelector mediaCodecSelector, Format format) {
return RendererCapabilities.create(C.FORMAT_HANDLED);
}
};
mediaCodecVideoRendererWithCustomAdapter.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
surface = new Surface(new SurfaceTexture(/* texName= */ 0));
mediaCodecVideoRendererWithCustomAdapter.handleMessage(Renderer.MSG_SET_VIDEO_OUTPUT, surface);
FakeSampleStream fakeSampleStream =
new FakeSampleStream(
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
/* mediaSourceEventDispatcher= */ null,
DrmSessionManager.DRM_UNSUPPORTED,
new DrmSessionEventListener.EventDispatcher(),
/* initialFormat= */ VIDEO_H264,
ImmutableList.of(
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */ 0);
mediaCodecVideoRendererWithCustomAdapter.enable(
RendererConfiguration.DEFAULT,
new Format[] {VIDEO_H264},
fakeSampleStream,
/* positionUs= */ 0,
/* joining= */ false,
/* mayRenderStartOfStream= */ true,
/* startPositionUs= */ 0,
/* offsetUs= */ 0,
new MediaSource.MediaPeriodId(new Object()));
mediaCodecVideoRendererWithCustomAdapter.setCurrentStreamFinal();
mediaCodecVideoRendererWithCustomAdapter.start();
int positionUs = 0;
do {
mediaCodecVideoRendererWithCustomAdapter.render(positionUs, SystemClock.elapsedRealtime() * 1000);
positionUs += 10;
} while (!mediaCodecVideoRendererWithCustomAdapter.isEnded());
shadowOf(testMainLooper).idle();
verify(eventListener)
.onVideoSizeChanged(
new VideoSize(
VIDEO_H264.width,
VIDEO_H264.height,
VIDEO_H264.pixelWidthHeightRatio / 2));
}
@Test
public void
render_withMultipleQueued_sendsVideoSizeChangedWithCorrectPixelAspectRatioWhenMultipleQueued()
@ -1901,9 +1968,31 @@ public class MediaCodecVideoRendererTest {
}
}
private static final class ForwardingSynchronousMediaCodecAdapterAlteringPixelAspectRatio
extends ForwardingSynchronousMediaCodecAdapter {
ForwardingSynchronousMediaCodecAdapterAlteringPixelAspectRatio(MediaCodecAdapter adapter) {
super(adapter);
}
@Override
public MediaFormat getOutputFormat() {
MediaFormat mediaFormat = adapter.getOutputFormat();
if (Util.SDK_INT >= 30) {
int pixelAspectRatioHeight = 1 << 30;
int pixelAspectRatioWidth = (int) (0.5f * pixelAspectRatioHeight);
mediaFormat.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH,
pixelAspectRatioWidth);
mediaFormat.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT,
pixelAspectRatioHeight);
}
return mediaFormat;
}
}
private abstract static class ForwardingSynchronousMediaCodecAdapter
implements MediaCodecAdapter {
private final MediaCodecAdapter adapter;
protected final MediaCodecAdapter adapter;
ForwardingSynchronousMediaCodecAdapter(MediaCodecAdapter adapter) {
this.adapter = adapter;