use of androidx.media3.exoplayer.audio.AudioSink in project media by androidx.
the class DefaultRenderersFactory method buildAudioRenderers.
/**
* Builds audio 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 audioSink A sink to which the renderers will output.
* @param eventHandler A handler to use when invoking event listeners and outputs.
* @param eventListener An event listener.
* @param out An array to which the built renderers should be appended.
*/
protected void buildAudioRenderers(Context context, @ExtensionRendererMode int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
MediaCodecAudioRenderer audioRenderer = new MediaCodecAudioRenderer(context, getCodecAdapterFactory(), mediaCodecSelector, enableDecoderFallback, eventHandler, eventListener, audioSink);
out.add(audioRenderer);
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.opus.LibopusAudioRenderer");
Constructor<?> constructor = clazz.getConstructor(android.os.Handler.class, androidx.media3.exoplayer.audio.AudioRendererEventListener.class, androidx.media3.exoplayer.audio.AudioSink.class);
Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded LibopusAudioRenderer.");
} 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 Opus 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.flac.LibflacAudioRenderer");
Constructor<?> constructor = clazz.getConstructor(android.os.Handler.class, androidx.media3.exoplayer.audio.AudioRendererEventListener.class, androidx.media3.exoplayer.audio.AudioSink.class);
Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded LibflacAudioRenderer.");
} 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 FLAC 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.ffmpeg.FfmpegAudioRenderer");
Constructor<?> constructor = clazz.getConstructor(android.os.Handler.class, androidx.media3.exoplayer.audio.AudioRendererEventListener.class, androidx.media3.exoplayer.audio.AudioSink.class);
Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded FfmpegAudioRenderer.");
} 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 FFmpeg extension", e);
}
}
use of androidx.media3.exoplayer.audio.AudioSink in project media by androidx.
the class LibflacAudioRenderer method supportsFormatInternal.
@Override
@C.FormatSupport
protected int supportsFormatInternal(Format format) {
if (!FlacLibrary.isAvailable() || !MimeTypes.AUDIO_FLAC.equalsIgnoreCase(format.sampleMimeType)) {
return C.FORMAT_UNSUPPORTED_TYPE;
}
// Compute the format that the FLAC decoder will output.
Format outputFormat;
if (format.initializationData.isEmpty()) {
// The initialization data might not be set if the format was obtained from a manifest (e.g.
// for DASH playbacks) rather than directly from the media. In this case we assume
// ENCODING_PCM_16BIT. If the actual encoding is different then playback will still succeed as
// long as the AudioSink supports it, which will always be true when using DefaultAudioSink.
outputFormat = Util.getPcmFormat(C.ENCODING_PCM_16BIT, format.channelCount, format.sampleRate);
} else {
int streamMetadataOffset = STREAM_MARKER_SIZE + METADATA_BLOCK_HEADER_SIZE;
FlacStreamMetadata streamMetadata = new FlacStreamMetadata(format.initializationData.get(0), streamMetadataOffset);
outputFormat = getOutputFormat(streamMetadata);
}
if (!sinkSupportsFormat(outputFormat)) {
return C.FORMAT_UNSUPPORTED_SUBTYPE;
} else if (format.cryptoType != C.CRYPTO_TYPE_NONE) {
return C.FORMAT_UNSUPPORTED_DRM;
} else {
return C.FORMAT_HANDLED;
}
}
use of androidx.media3.exoplayer.audio.AudioSink in project media by androidx.
the class MediaCodecAudioRenderer method supportsFormat.
@Override
@Capabilities
protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format) throws DecoderQueryException {
if (!MimeTypes.isAudio(format.sampleMimeType)) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
}
@TunnelingSupport int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
boolean formatHasDrm = format.cryptoType != C.CRYPTO_TYPE_NONE;
boolean supportsFormatDrm = supportsFormatDrm(format);
// Else we don't don't need a decoder at all.
if (supportsFormatDrm && audioSink.supportsFormat(format) && (!formatHasDrm || MediaCodecUtil.getDecryptOnlyDecoderInfo() != null)) {
return RendererCapabilities.create(C.FORMAT_HANDLED, ADAPTIVE_NOT_SEAMLESS, tunnelingSupport);
}
// the input format directly.
if (MimeTypes.AUDIO_RAW.equals(format.sampleMimeType) && !audioSink.supportsFormat(format)) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
// For all other input formats, we expect the decoder to output 16-bit PCM.
if (!audioSink.supportsFormat(Util.getPcmFormat(C.ENCODING_PCM_16BIT, format.channelCount, format.sampleRate))) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
List<MediaCodecInfo> decoderInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */
false, audioSink);
if (decoderInfos.isEmpty()) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
if (!supportsFormatDrm) {
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 = isFormatSupported && 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;
return RendererCapabilities.create(formatSupport, adaptiveSupport, tunnelingSupport, hardwareAccelerationSupport, decoderSupport);
}
use of androidx.media3.exoplayer.audio.AudioSink in project media by androidx.
the class MediaCodecAudioRendererTest method render_configuresAudioSink_afterFormatChange.
@Test
public void render_configuresAudioSink_afterFormatChange() throws Exception {
Format changedFormat = AUDIO_AAC.buildUpon().setSampleRate(48_000).setEncoderDelay(400).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), oneByteSample(/* timeUs= */
50, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */
100, C.BUFFER_FLAG_KEY_FRAME), format(changedFormat), oneByteSample(/* timeUs= */
150, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */
200, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */
250, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
fakeSampleStream.writeData(/* startPositionUs= */
0);
mediaCodecAudioRenderer.enable(RendererConfiguration.DEFAULT, new Format[] { AUDIO_AAC, changedFormat }, fakeSampleStream, /* positionUs= */
0, /* joining= */
false, /* mayRenderStartOfStream= */
false, /* startPositionUs= */
0, /* offsetUs */
0);
mediaCodecAudioRenderer.start();
mediaCodecAudioRenderer.render(/* positionUs= */
0, SystemClock.elapsedRealtime() * 1000);
mediaCodecAudioRenderer.render(/* positionUs= */
250, SystemClock.elapsedRealtime() * 1000);
mediaCodecAudioRenderer.setCurrentStreamFinal();
int positionUs = 500;
do {
mediaCodecAudioRenderer.render(positionUs, SystemClock.elapsedRealtime() * 1000);
positionUs += 250;
} while (!mediaCodecAudioRenderer.isEnded());
verify(audioSink).configure(getAudioSinkFormat(AUDIO_AAC), /* specifiedBufferSize= */
0, /* outputChannels= */
null);
verify(audioSink).configure(getAudioSinkFormat(changedFormat), /* specifiedBufferSize= */
0, /* outputChannels= */
null);
}
use of androidx.media3.exoplayer.audio.AudioSink in project media by androidx.
the class MediaCodecAudioRendererTest method supportsFormat_withEac3JocMediaAndEac3Decoder_returnsTrue.
@Test
public void supportsFormat_withEac3JocMediaAndEac3Decoder_returnsTrue() throws Exception {
Format mediaFormat = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_E_AC3_JOC).setCodecs(MimeTypes.CODEC_E_AC3_JOC).build();
MediaCodecSelector mediaCodecSelector = (mimeType, requiresSecureDecoder, requiresTunnelingDecoder) -> !mimeType.equals(MimeTypes.AUDIO_E_AC3) ? ImmutableList.of() : ImmutableList.of(MediaCodecInfo.newInstance(/* name= */
"eac3-codec", /* mimeType= */
mimeType, /* codecMimeType= */
mimeType, /* capabilities= */
null, /* hardwareAccelerated= */
false, /* softwareOnly= */
true, /* vendor= */
false, /* forceDisableAdaptive= */
false, /* forceSecure= */
false));
MediaCodecAudioRenderer renderer = new MediaCodecAudioRenderer(ApplicationProvider.getApplicationContext(), mediaCodecSelector, /* enableDecoderFallback= */
false, /* eventHandler= */
new Handler(Looper.getMainLooper()), audioRendererEventListener, audioSink);
renderer.init(/* index= */
0, PlayerId.UNSET);
@Capabilities int capabilities = renderer.supportsFormat(mediaFormat);
assertThat(RendererCapabilities.getFormatSupport(capabilities)).isEqualTo(C.FORMAT_HANDLED);
}
Aggregations