use of com.google.android.exoplayer2.RendererCapabilities.Capabilities in project ExoPlayer by google.
the class DefaultTrackSelectorTest method selectTracksExceedingCapabilitiesPreferLowerNumChannelBeforeSampleRate.
/**
* Tests that track selector will prefer audio tracks with lower channel count over tracks with
* lower sample rate when other factors are the same, and tracks are within renderer's
* capabilities.
*/
@Test
public void selectTracksExceedingCapabilitiesPreferLowerNumChannelBeforeSampleRate() throws Exception {
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
Format lowerChannelHigherSampleRateFormat = formatBuilder.setChannelCount(2).setSampleRate(44100).build();
Format higherChannelLowerSampleRateFormat = formatBuilder.setChannelCount(6).setSampleRate(22050).build();
TrackGroupArray trackGroups = wrapFormats(higherChannelLowerSampleRateFormat, lowerChannelHigherSampleRateFormat);
TrackSelectorResult result = trackSelector.selectTracks(new RendererCapabilities[] { ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES }, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, lowerChannelHigherSampleRateFormat);
}
use of com.google.android.exoplayer2.RendererCapabilities.Capabilities in project ExoPlayer by google.
the class DecoderVideoRendererTest method setUp.
@Before
public void setUp() {
surface = new Surface(new SurfaceTexture(/* texName= */
0));
renderer = new DecoderVideoRenderer(/* allowedJoiningTimeMs= */
0, new Handler(), eventListener, /* maxDroppedFramesToNotify= */
-1) {
private final Phaser inputBuffersInCodecPhaser = new Phaser();
@C.VideoOutputMode
private int outputMode;
@Override
public String getName() {
return "TestVideoRenderer";
}
@Override
@Capabilities
public int supportsFormat(Format format) {
return RendererCapabilities.create(C.FORMAT_HANDLED);
}
@Override
protected void setDecoderOutputMode(@C.VideoOutputMode int outputMode) {
this.outputMode = outputMode;
}
@Override
protected void renderOutputBufferToSurface(VideoDecoderOutputBuffer outputBuffer, Surface surface) {
// Do nothing.
}
@Override
protected void onQueueInputBuffer(DecoderInputBuffer buffer) {
// Decoding is done on a background thread we have no control about from the test.
// Ensure the background calls are predictably serialized by waiting for them to finish:
// 1. Register queued input buffers here.
// 2. Deregister the input buffer when it's cleared. If an input buffer is cleared it
// will have been fully handled by the decoder.
// 3. Send a message on the test thread to wait for all currently pending input buffers
// to be cleared.
// 4. The tests need to call ShadowLooper.idleMainThread() to execute the wait message
// sent in step (3).
int currentPhase = inputBuffersInCodecPhaser.register();
new Handler().post(() -> inputBuffersInCodecPhaser.awaitAdvance(currentPhase));
super.onQueueInputBuffer(buffer);
}
@Override
protected SimpleDecoder<DecoderInputBuffer, ? extends VideoDecoderOutputBuffer, ? extends DecoderException> createDecoder(Format format, @Nullable CryptoConfig cryptoConfig) {
return new SimpleDecoder<DecoderInputBuffer, VideoDecoderOutputBuffer, DecoderException>(new DecoderInputBuffer[10], new VideoDecoderOutputBuffer[10]) {
@Override
protected DecoderInputBuffer createInputBuffer() {
return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT) {
@Override
public void clear() {
super.clear();
inputBuffersInCodecPhaser.arriveAndDeregister();
}
};
}
@Override
protected VideoDecoderOutputBuffer createOutputBuffer() {
return new VideoDecoderOutputBuffer(this::releaseOutputBuffer);
}
@Override
protected DecoderException createUnexpectedDecodeException(Throwable error) {
return new DecoderException("error", error);
}
@Nullable
@Override
protected DecoderException decode(DecoderInputBuffer inputBuffer, VideoDecoderOutputBuffer outputBuffer, boolean reset) {
outputBuffer.init(inputBuffer.timeUs, outputMode, /* supplementalData= */
null);
return null;
}
@Override
public String getName() {
return "TestDecoder";
}
};
}
};
renderer.setOutput(surface);
}
use of com.google.android.exoplayer2.RendererCapabilities.Capabilities in project ExoPlayer by google.
the class FakeTrackSelector method selectAllTracks.
@Override
protected ExoTrackSelection.@NullableType Definition[] selectAllTracks(MappedTrackInfo mappedTrackInfo, @Capabilities int[][][] rendererFormatSupports, @AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupports, Parameters params) {
int rendererCount = mappedTrackInfo.getRendererCount();
ExoTrackSelection.@NullableType Definition[] definitions = new ExoTrackSelection.Definition[rendererCount];
for (int i = 0; i < rendererCount; i++) {
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
boolean hasTracks = trackGroupArray.length > 0;
definitions[i] = hasTracks ? new ExoTrackSelection.Definition(trackGroupArray.get(0)) : null;
}
return definitions;
}
use of com.google.android.exoplayer2.RendererCapabilities.Capabilities in project ExoPlayer by google.
the class MappingTrackSelector method selectTracks.
@Override
public final TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups, MediaPeriodId periodId, Timeline timeline) throws ExoPlaybackException {
// Structures into which data will be written during the selection. The extra item at the end
// of each array is to store data associated with track groups that cannot be associated with
// any renderer.
int[] rendererTrackGroupCounts = new int[rendererCapabilities.length + 1];
TrackGroup[][] rendererTrackGroups = new TrackGroup[rendererCapabilities.length + 1][];
@Capabilities int[][][] rendererFormatSupports = new int[rendererCapabilities.length + 1][][];
for (int i = 0; i < rendererTrackGroups.length; i++) {
rendererTrackGroups[i] = new TrackGroup[trackGroups.length];
rendererFormatSupports[i] = new int[trackGroups.length][];
}
// Determine the extent to which each renderer supports mixed mimeType adaptation.
@AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupports = getMixedMimeTypeAdaptationSupports(rendererCapabilities);
// renderer provides for each track in the group.
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup group = trackGroups.get(groupIndex);
// Associate the group to a preferred renderer.
boolean preferUnassociatedRenderer = MimeTypes.getTrackType(group.getFormat(0).sampleMimeType) == C.TRACK_TYPE_METADATA;
int rendererIndex = findRenderer(rendererCapabilities, group, rendererTrackGroupCounts, preferUnassociatedRenderer);
// Evaluate the support that the renderer provides for each track in the group.
@Capabilities int[] rendererFormatSupport = rendererIndex == rendererCapabilities.length ? new int[group.length] : getFormatSupport(rendererCapabilities[rendererIndex], group);
// Stash the results.
int rendererTrackGroupCount = rendererTrackGroupCounts[rendererIndex];
rendererTrackGroups[rendererIndex][rendererTrackGroupCount] = group;
rendererFormatSupports[rendererIndex][rendererTrackGroupCount] = rendererFormatSupport;
rendererTrackGroupCounts[rendererIndex]++;
}
// Create a track group array for each renderer, and trim each rendererFormatSupports entry.
TrackGroupArray[] rendererTrackGroupArrays = new TrackGroupArray[rendererCapabilities.length];
String[] rendererNames = new String[rendererCapabilities.length];
int[] rendererTrackTypes = new int[rendererCapabilities.length];
for (int i = 0; i < rendererCapabilities.length; i++) {
int rendererTrackGroupCount = rendererTrackGroupCounts[i];
rendererTrackGroupArrays[i] = new TrackGroupArray(Util.nullSafeArrayCopy(rendererTrackGroups[i], rendererTrackGroupCount));
rendererFormatSupports[i] = Util.nullSafeArrayCopy(rendererFormatSupports[i], rendererTrackGroupCount);
rendererNames[i] = rendererCapabilities[i].getName();
rendererTrackTypes[i] = rendererCapabilities[i].getTrackType();
}
// Create a track group array for track groups not mapped to a renderer.
int unmappedTrackGroupCount = rendererTrackGroupCounts[rendererCapabilities.length];
TrackGroupArray unmappedTrackGroupArray = new TrackGroupArray(Util.nullSafeArrayCopy(rendererTrackGroups[rendererCapabilities.length], unmappedTrackGroupCount));
// Package up the track information and selections.
MappedTrackInfo mappedTrackInfo = new MappedTrackInfo(rendererNames, rendererTrackTypes, rendererTrackGroupArrays, rendererMixedMimeTypeAdaptationSupports, rendererFormatSupports, unmappedTrackGroupArray);
Pair<@NullableType RendererConfiguration[], @NullableType ExoTrackSelection[]> result = selectTracks(mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports, periodId, timeline);
TracksInfo tracksInfo = buildTracksInfo(result.second, mappedTrackInfo);
return new TrackSelectorResult(result.first, result.second, tracksInfo, mappedTrackInfo);
}
use of com.google.android.exoplayer2.RendererCapabilities.Capabilities in project ExoPlayer by google.
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