use of androidx.media3.exoplayer.mediacodec.MediaCodecSelector in project media by androidx.
the class MediaCodecVideoRenderer method supportsFormat.
@Override
@Capabilities
protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format) throws DecoderQueryException {
String mimeType = format.sampleMimeType;
if (!MimeTypes.isVideo(mimeType)) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
}
@Nullable DrmInitData drmInitData = format.drmInitData;
// Assume encrypted content requires secure decoders.
boolean requiresSecureDecryption = drmInitData != null;
List<MediaCodecInfo> decoderInfos = getDecoderInfos(mediaCodecSelector, format, requiresSecureDecryption, /* requiresTunnelingDecoder= */
false);
if (requiresSecureDecryption && decoderInfos.isEmpty()) {
// No secure decoders are available. Fall back to non-secure decoders.
decoderInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */
false, /* requiresTunnelingDecoder= */
false);
}
if (decoderInfos.isEmpty()) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
if (!supportsFormatDrm(format)) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_DRM);
}
// Check whether the first decoder supports the format. This is the preferred decoder for the
// format's MIME type, according to the MediaCodecSelector.
MediaCodecInfo decoderInfo = decoderInfos.get(0);
boolean isFormatSupported = decoderInfo.isFormatSupported(format);
boolean isPreferredDecoder = true;
if (!isFormatSupported) {
// Check whether any of the other decoders support the format.
for (int i = 1; i < decoderInfos.size(); i++) {
MediaCodecInfo otherDecoderInfo = decoderInfos.get(i);
if (otherDecoderInfo.isFormatSupported(format)) {
decoderInfo = otherDecoderInfo;
isFormatSupported = true;
isPreferredDecoder = false;
break;
}
}
}
@C.FormatSupport int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES;
@AdaptiveSupport int adaptiveSupport = decoderInfo.isSeamlessAdaptationSupported(format) ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS;
@HardwareAccelerationSupport int hardwareAccelerationSupport = decoderInfo.hardwareAccelerated ? HARDWARE_ACCELERATION_SUPPORTED : HARDWARE_ACCELERATION_NOT_SUPPORTED;
@DecoderSupport int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK;
@TunnelingSupport int tunnelingSupport = TUNNELING_NOT_SUPPORTED;
if (isFormatSupported) {
List<MediaCodecInfo> tunnelingDecoderInfos = getDecoderInfos(mediaCodecSelector, format, requiresSecureDecryption, /* requiresTunnelingDecoder= */
true);
if (!tunnelingDecoderInfos.isEmpty()) {
MediaCodecInfo tunnelingDecoderInfo = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(tunnelingDecoderInfos, format).get(0);
if (tunnelingDecoderInfo.isFormatSupported(format) && tunnelingDecoderInfo.isSeamlessAdaptationSupported(format)) {
tunnelingSupport = TUNNELING_SUPPORTED;
}
}
}
return RendererCapabilities.create(formatSupport, adaptiveSupport, tunnelingSupport, hardwareAccelerationSupport, decoderSupport);
}
use of androidx.media3.exoplayer.mediacodec.MediaCodecSelector in project media by androidx.
the class DefaultRenderersFactory method createRenderers.
@Override
public Renderer[] createRenderers(Handler eventHandler, VideoRendererEventListener videoRendererEventListener, AudioRendererEventListener audioRendererEventListener, TextOutput textRendererOutput, MetadataOutput metadataRendererOutput) {
ArrayList<Renderer> renderersList = new ArrayList<>();
buildVideoRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, eventHandler, videoRendererEventListener, allowedVideoJoiningTimeMs, renderersList);
@Nullable AudioSink audioSink = buildAudioSink(context, enableFloatOutput, enableAudioTrackPlaybackParams, enableOffload);
if (audioSink != null) {
buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, audioRendererEventListener, renderersList);
}
buildTextRenderers(context, textRendererOutput, eventHandler.getLooper(), extensionRendererMode, renderersList);
buildMetadataRenderers(context, metadataRendererOutput, eventHandler.getLooper(), extensionRendererMode, renderersList);
buildCameraMotionRenderers(context, extensionRendererMode, renderersList);
buildMiscellaneousRenderers(context, eventHandler, extensionRendererMode, renderersList);
return renderersList.toArray(new Renderer[0]);
}
use of androidx.media3.exoplayer.mediacodec.MediaCodecSelector in project media by androidx.
the class DefaultRenderersFactory method buildVideoRenderers.
/**
* Builds video renderers for use by the player.
*
* @param context The {@link Context} associated with the player.
* @param extensionRendererMode The extension renderer mode.
* @param mediaCodecSelector A decoder selector.
* @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
* initialization fails. This may result in using a decoder that is slower/less efficient than
* the primary decoder.
* @param eventHandler A handler associated with the main thread's looper.
* @param eventListener An event listener.
* @param allowedVideoJoiningTimeMs The maximum duration for which video renderers can attempt to
* seamlessly join an ongoing playback, in milliseconds.
* @param out An array to which the built renderers should be appended.
*/
protected void buildVideoRenderers(Context context, @ExtensionRendererMode int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, Handler eventHandler, VideoRendererEventListener eventListener, long allowedVideoJoiningTimeMs, ArrayList<Renderer> out) {
MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer(context, getCodecAdapterFactory(), mediaCodecSelector, allowedVideoJoiningTimeMs, enableDecoderFallback, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
out.add(videoRenderer);
if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
return;
}
int extensionRendererIndex = out.size();
if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {
extensionRendererIndex--;
}
try {
// Full class names used for constructor args so the LINT rule triggers if any of them move.
Class<?> clazz = Class.forName("androidx.media3.decoder.vp9.LibvpxVideoRenderer");
Constructor<?> constructor = clazz.getConstructor(long.class, android.os.Handler.class, androidx.media3.exoplayer.video.VideoRendererEventListener.class, int.class);
Renderer renderer = (Renderer) constructor.newInstance(allowedVideoJoiningTimeMs, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded LibvpxVideoRenderer.");
} catch (ClassNotFoundException e) {
// Expected if the app was built without the extension.
} catch (Exception e) {
// The extension is present, but instantiation failed.
throw new RuntimeException("Error instantiating VP9 extension", e);
}
try {
// Full class names used for constructor args so the LINT rule triggers if any of them move.
Class<?> clazz = Class.forName("androidx.media3.decoder.av1.Libgav1VideoRenderer");
Constructor<?> constructor = clazz.getConstructor(long.class, android.os.Handler.class, androidx.media3.exoplayer.video.VideoRendererEventListener.class, int.class);
Renderer renderer = (Renderer) constructor.newInstance(allowedVideoJoiningTimeMs, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded Libgav1VideoRenderer.");
} catch (ClassNotFoundException e) {
// Expected if the app was built without the extension.
} catch (Exception e) {
// The extension is present, but instantiation failed.
throw new RuntimeException("Error instantiating AV1 extension", e);
}
}
use of androidx.media3.exoplayer.mediacodec.MediaCodecSelector in project media by androidx.
the class MediaCodecAudioRendererTest method render_throwsExoPlaybackExceptionJustOnce_whenSet.
@Test
public void render_throwsExoPlaybackExceptionJustOnce_whenSet() throws Exception {
MediaCodecAudioRenderer exceptionThrowingRenderer = new MediaCodecAudioRenderer(ApplicationProvider.getApplicationContext(), mediaCodecSelector, /* eventHandler= */
null, /* eventListener= */
null) {
@Override
protected void onOutputFormatChanged(Format format, @Nullable MediaFormat mediaFormat) throws ExoPlaybackException {
super.onOutputFormatChanged(format, mediaFormat);
if (!format.equals(AUDIO_AAC)) {
setPendingPlaybackException(ExoPlaybackException.createForRenderer(new AudioSink.ConfigurationException("Test", format), "rendererName", /* rendererIndex= */
0, format, C.FORMAT_HANDLED, /* isRecoverable= */
false, PlaybackException.ERROR_CODE_UNSPECIFIED));
}
}
};
Format changedFormat = AUDIO_AAC.buildUpon().setSampleRate(32_000).build();
FakeSampleStream fakeSampleStream = new FakeSampleStream(new DefaultAllocator(/* trimOnReset= */
true, /* individualAllocationSize= */
1024), /* mediaSourceEventDispatcher= */
null, DrmSessionManager.DRM_UNSUPPORTED, new DrmSessionEventListener.EventDispatcher(), /* initialFormat= */
AUDIO_AAC, ImmutableList.of(oneByteSample(/* timeUs= */
0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */
0);
exceptionThrowingRenderer.init(/* index= */
0, PlayerId.UNSET);
exceptionThrowingRenderer.enable(RendererConfiguration.DEFAULT, new Format[] { AUDIO_AAC, changedFormat }, fakeSampleStream, /* positionUs= */
0, /* joining= */
false, /* mayRenderStartOfStream= */
false, /* startPositionUs= */
0, /* offsetUs */
0);
exceptionThrowingRenderer.start();
exceptionThrowingRenderer.render(/* positionUs= */
0, SystemClock.elapsedRealtime() * 1000);
exceptionThrowingRenderer.render(/* positionUs= */
250, SystemClock.elapsedRealtime() * 1000);
MediaFormat mediaFormat = new MediaFormat();
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 32_000);
// Simulating the exception being thrown when not traceable back to render.
exceptionThrowingRenderer.onOutputFormatChanged(changedFormat, mediaFormat);
assertThrows(ExoPlaybackException.class, () -> exceptionThrowingRenderer.render(/* positionUs= */
500, SystemClock.elapsedRealtime() * 1000));
// Doesn't throw an exception because it's cleared after being thrown in the previous call to
// render.
exceptionThrowingRenderer.render(/* positionUs= */
750, SystemClock.elapsedRealtime() * 1000);
}
use of androidx.media3.exoplayer.mediacodec.MediaCodecSelector in project media by androidx.
the class MediaCodecAudioRendererTest method setUp.
@Before
public void setUp() throws Exception {
// audioSink isEnded can always be true because the MediaCodecAudioRenderer isEnded =
// super.isEnded && audioSink.isEnded.
when(audioSink.isEnded()).thenReturn(true);
when(audioSink.handleBuffer(any(), anyLong(), anyInt())).thenReturn(true);
when(audioSink.supportsFormat(any())).thenAnswer(invocation -> {
Format format = invocation.getArgument(/* index= */
0, Format.class);
return MimeTypes.AUDIO_RAW.equals(format.sampleMimeType) && format.pcmEncoding == C.ENCODING_PCM_16BIT;
});
mediaCodecSelector = (mimeType, requiresSecureDecoder, requiresTunnelingDecoder) -> Collections.singletonList(MediaCodecInfo.newInstance(/* name= */
"name", /* mimeType= */
mimeType, /* codecMimeType= */
mimeType, /* capabilities= */
null, /* hardwareAccelerated= */
false, /* softwareOnly= */
true, /* vendor= */
false, /* forceDisableAdaptive= */
false, /* forceSecure= */
false));
Handler eventHandler = new Handler(Looper.getMainLooper());
mediaCodecAudioRenderer = new MediaCodecAudioRenderer(ApplicationProvider.getApplicationContext(), mediaCodecSelector, /* enableDecoderFallback= */
false, eventHandler, audioRendererEventListener, audioSink);
mediaCodecAudioRenderer.init(/* index= */
0, PlayerId.UNSET);
}
Aggregations