use of com.google.android.exoplayer2.C in project ExoPlayer by google.
the class DefaultTrackSelectorTest method selectTracksSelectPreferredAudioLanguageOverSelectionFlag.
/**
* Tests that track selector will prefer selecting audio track with language that match preferred
* language given by {@link Parameters} over track with {@link C#SELECTION_FLAG_DEFAULT}.
*/
@Test
public void selectTracksSelectPreferredAudioLanguageOverSelectionFlag() throws Exception {
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
Format frDefaultFormat = formatBuilder.setLanguage("fra").setSelectionFlags(C.SELECTION_FLAG_DEFAULT).build();
Format enNonDefaultFormat = formatBuilder.setLanguage("eng").setSelectionFlags(0).build();
TrackGroupArray trackGroups = wrapFormats(frDefaultFormat, enNonDefaultFormat);
trackSelector.setParameters(defaultParameters.buildUpon().setPreferredAudioLanguage("eng"));
TrackSelectorResult result = trackSelector.selectTracks(new RendererCapabilities[] { ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES }, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, enNonDefaultFormat);
}
use of com.google.android.exoplayer2.C in project ExoPlayer by google.
the class CacheWriter method readBlockToCache.
/**
* Reads the specified block of data, writing it into the cache.
*
* @param position The starting position of the block.
* @param length The length of the block, or {@link C#LENGTH_UNSET} if unbounded.
* @return The number of bytes read.
* @throws IOException If an error occurs reading the data or writing it to the cache.
*/
private long readBlockToCache(long position, long length) throws IOException {
boolean isLastBlock = position + length == endPosition || length == C.LENGTH_UNSET;
long resolvedLength = C.LENGTH_UNSET;
boolean isDataSourceOpen = false;
if (length != C.LENGTH_UNSET) {
// If the length is specified, try to open the data source with a bounded request to avoid
// the underlying network stack requesting more data than required.
DataSpec boundedDataSpec = dataSpec.buildUpon().setPosition(position).setLength(length).build();
try {
resolvedLength = dataSource.open(boundedDataSpec);
isDataSourceOpen = true;
} catch (IOException e) {
DataSourceUtil.closeQuietly(dataSource);
}
}
if (!isDataSourceOpen) {
// Either the length was unspecified, or we allow short content and our attempt to open the
// DataSource with the specified length failed.
throwIfCanceled();
DataSpec unboundedDataSpec = dataSpec.buildUpon().setPosition(position).setLength(C.LENGTH_UNSET).build();
try {
resolvedLength = dataSource.open(unboundedDataSpec);
} catch (IOException e) {
DataSourceUtil.closeQuietly(dataSource);
throw e;
}
}
int totalBytesRead = 0;
try {
if (isLastBlock && resolvedLength != C.LENGTH_UNSET) {
onRequestEndPosition(position + resolvedLength);
}
int bytesRead = 0;
while (bytesRead != C.RESULT_END_OF_INPUT) {
throwIfCanceled();
bytesRead = dataSource.read(temporaryBuffer, /* offset= */
0, temporaryBuffer.length);
if (bytesRead != C.RESULT_END_OF_INPUT) {
onNewBytesCached(bytesRead);
totalBytesRead += bytesRead;
}
}
if (isLastBlock) {
onRequestEndPosition(position + totalBytesRead);
}
} catch (IOException e) {
DataSourceUtil.closeQuietly(dataSource);
throw e;
}
// Util.closeQuietly(dataSource) is not used here because it's important that an exception is
// thrown if DataSource.close fails. This is because there's no way of knowing whether the block
// was successfully cached in this case.
dataSource.close();
return totalBytesRead;
}
use of com.google.android.exoplayer2.C in project ExoPlayer by google.
the class DefaultHttpDataSource method maybeTerminateInputStream.
/**
* On platform API levels 19 and 20, okhttp's implementation of {@link InputStream#close} can
* block for a long time if the stream has a lot of data remaining. Call this method before
* closing the input stream to make a best effort to cause the input stream to encounter an
* unexpected end of input, working around this issue. On other platform API levels, the method
* does nothing.
*
* @param connection The connection whose {@link InputStream} should be terminated.
* @param bytesRemaining The number of bytes remaining to be read from the input stream if its
* length is known. {@link C#LENGTH_UNSET} otherwise.
*/
private static void maybeTerminateInputStream(@Nullable HttpURLConnection connection, long bytesRemaining) {
if (connection == null || Util.SDK_INT < 19 || Util.SDK_INT > 20) {
return;
}
try {
InputStream inputStream = connection.getInputStream();
if (bytesRemaining == C.LENGTH_UNSET) {
// If the input stream has already ended, do nothing. The socket may be re-used.
if (inputStream.read() == -1) {
return;
}
} else if (bytesRemaining <= MAX_BYTES_TO_DRAIN) {
// re-used.
return;
}
String className = inputStream.getClass().getName();
if ("com.android.okhttp.internal.http.HttpTransport$ChunkedInputStream".equals(className) || "com.android.okhttp.internal.http.HttpTransport$FixedLengthInputStream".equals(className)) {
Class<?> superclass = inputStream.getClass().getSuperclass();
Method unexpectedEndOfInput = checkNotNull(superclass).getDeclaredMethod("unexpectedEndOfInput");
unexpectedEndOfInput.setAccessible(true);
unexpectedEndOfInput.invoke(inputStream);
}
} catch (Exception e) {
// If an IOException then the connection didn't ever have an input stream, or it was closed
// already. If another type of exception then something went wrong, most likely the device
// isn't using okhttp.
}
}
use of com.google.android.exoplayer2.C in project ExoPlayer by google.
the class AdaptiveTrackSelection method determineIdealSelectedIndex.
/**
* Computes the ideal selected index ignoring buffer health.
*
* @param nowMs The current time in the timebase of {@link Clock#elapsedRealtime()}, or {@link
* Long#MIN_VALUE} to ignore track exclusion.
* @param chunkDurationUs The duration of a media chunk in microseconds, or {@link C#TIME_UNSET}
* if unknown.
*/
private int determineIdealSelectedIndex(long nowMs, long chunkDurationUs) {
long effectiveBitrate = getAllocatedBandwidth(chunkDurationUs);
int lowestBitrateAllowedIndex = 0;
for (int i = 0; i < length; i++) {
if (nowMs == Long.MIN_VALUE || !isBlacklisted(i, nowMs)) {
Format format = getFormat(i);
if (canSelectFormat(format, format.bitrate, effectiveBitrate)) {
return i;
} else {
lowestBitrateAllowedIndex = i;
}
}
}
return lowestBitrateAllowedIndex;
}
use of com.google.android.exoplayer2.C in project ExoPlayer by google.
the class MappingTrackSelector method findRenderer.
/**
* Finds the renderer to which the provided {@link TrackGroup} should be mapped.
*
* <p>A {@link TrackGroup} is mapped to the renderer that reports the highest of (listed in
* decreasing order of support) {@link C#FORMAT_HANDLED}, {@link C#FORMAT_EXCEEDS_CAPABILITIES},
* {@link C#FORMAT_UNSUPPORTED_DRM} and {@link C#FORMAT_UNSUPPORTED_SUBTYPE}.
*
* <p>In the case that two or more renderers report the same level of support, the assignment
* depends on {@code preferUnassociatedRenderer}.
*
* <ul>
* <li>If {@code preferUnassociatedRenderer} is false, the renderer with the lowest index is
* chosen regardless of how many other track groups are already mapped to this renderer.
* <li>If {@code preferUnassociatedRenderer} is true, the renderer with the lowest index and no
* other mapped track group is chosen, or the renderer with the lowest index if all
* available renderers have already mapped track groups.
* </ul>
*
* <p>If all renderers report {@link C#FORMAT_UNSUPPORTED_TYPE} for all of the tracks in the
* group, then {@code renderers.length} is returned to indicate that the group was not mapped to
* any renderer.
*
* @param rendererCapabilities The {@link RendererCapabilities} of the renderers.
* @param group The track group to map to a renderer.
* @param rendererTrackGroupCounts The number of already mapped track groups for each renderer.
* @param preferUnassociatedRenderer Whether renderers unassociated to any track group should be
* preferred.
* @return The index of the renderer to which the track group was mapped, or {@code
* renderers.length} if it was not mapped to any renderer.
* @throws ExoPlaybackException If an error occurs finding a renderer.
*/
private static int findRenderer(RendererCapabilities[] rendererCapabilities, TrackGroup group, int[] rendererTrackGroupCounts, boolean preferUnassociatedRenderer) throws ExoPlaybackException {
int bestRendererIndex = rendererCapabilities.length;
@FormatSupport int bestFormatSupportLevel = C.FORMAT_UNSUPPORTED_TYPE;
boolean bestRendererIsUnassociated = true;
for (int rendererIndex = 0; rendererIndex < rendererCapabilities.length; rendererIndex++) {
RendererCapabilities rendererCapability = rendererCapabilities[rendererIndex];
@FormatSupport int formatSupportLevel = C.FORMAT_UNSUPPORTED_TYPE;
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
@FormatSupport int trackFormatSupportLevel = RendererCapabilities.getFormatSupport(rendererCapability.supportsFormat(group.getFormat(trackIndex)));
formatSupportLevel = max(formatSupportLevel, trackFormatSupportLevel);
}
boolean rendererIsUnassociated = rendererTrackGroupCounts[rendererIndex] == 0;
if (formatSupportLevel > bestFormatSupportLevel || (formatSupportLevel == bestFormatSupportLevel && preferUnassociatedRenderer && !bestRendererIsUnassociated && rendererIsUnassociated)) {
bestRendererIndex = rendererIndex;
bestFormatSupportLevel = formatSupportLevel;
bestRendererIsUnassociated = rendererIsUnassociated;
}
}
return bestRendererIndex;
}
Aggregations