use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class ProgressiveMediaPeriod method selectTracks.
@Override
public long selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
assertPrepared();
TrackGroupArray tracks = trackState.tracks;
boolean[] trackEnabledStates = trackState.trackEnabledStates;
int oldEnabledTrackCount = enabledTrackCount;
// Deselect old tracks.
for (int i = 0; i < selections.length; i++) {
if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
int track = ((SampleStreamImpl) streams[i]).track;
Assertions.checkState(trackEnabledStates[track]);
enabledTrackCount--;
trackEnabledStates[track] = false;
streams[i] = null;
}
}
// We'll always need to seek if this is a first selection to a non-zero position, or if we're
// making a selection having previously disabled all tracks.
boolean seekRequired = seenFirstTrackSelection ? oldEnabledTrackCount == 0 : positionUs != 0;
// Select new tracks.
for (int i = 0; i < selections.length; i++) {
if (streams[i] == null && selections[i] != null) {
ExoTrackSelection selection = selections[i];
Assertions.checkState(selection.length() == 1);
Assertions.checkState(selection.getIndexInTrackGroup(0) == 0);
int track = tracks.indexOf(selection.getTrackGroup());
Assertions.checkState(!trackEnabledStates[track]);
enabledTrackCount++;
trackEnabledStates[track] = true;
streams[i] = new SampleStreamImpl(track);
streamResetFlags[i] = true;
// If there's still a chance of avoiding a seek, try and seek within the sample queue.
if (!seekRequired) {
SampleQueue sampleQueue = sampleQueues[track];
// A seek can be avoided if we're able to seek to the current playback position in the
// sample queue, or if we haven't read anything from the queue since the previous seek
// (this case is common for sparse tracks such as metadata tracks). In all other cases a
// seek is required.
seekRequired = !sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */
true) && sampleQueue.getReadIndex() != 0;
}
}
}
if (enabledTrackCount == 0) {
pendingDeferredRetry = false;
notifyDiscontinuity = false;
if (loader.isLoading()) {
// Discard as much as we can synchronously.
for (SampleQueue sampleQueue : sampleQueues) {
sampleQueue.discardToEnd();
}
loader.cancelLoading();
} else {
for (SampleQueue sampleQueue : sampleQueues) {
sampleQueue.reset();
}
}
} else if (seekRequired) {
positionUs = seekToUs(positionUs);
// We'll need to reset renderers consuming from all streams due to the seek.
for (int i = 0; i < streams.length; i++) {
if (streams[i] != null) {
streamResetFlags[i] = true;
}
}
}
seenFirstTrackSelection = true;
return positionUs;
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class ChunkSampleStream method onLoadError.
@Override
public LoadErrorAction onLoadError(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error, int errorCount) {
long bytesLoaded = loadable.bytesLoaded();
boolean isMediaChunk = isMediaChunk(loadable);
int lastChunkIndex = mediaChunks.size() - 1;
boolean cancelable = bytesLoaded == 0 || !isMediaChunk || !haveReadFromMediaChunk(lastChunkIndex);
LoadEventInfo loadEventInfo = new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, loadable.getUri(), loadable.getResponseHeaders(), elapsedRealtimeMs, loadDurationMs, bytesLoaded);
MediaLoadData mediaLoadData = new MediaLoadData(loadable.type, primaryTrackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, Util.usToMs(loadable.startTimeUs), Util.usToMs(loadable.endTimeUs));
LoadErrorInfo loadErrorInfo = new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
@Nullable LoadErrorAction loadErrorAction = null;
if (chunkSource.onChunkLoadError(loadable, cancelable, loadErrorInfo, loadErrorHandlingPolicy)) {
if (cancelable) {
loadErrorAction = Loader.DONT_RETRY;
if (isMediaChunk) {
BaseMediaChunk removed = discardUpstreamMediaChunksFromIndex(lastChunkIndex);
Assertions.checkState(removed == loadable);
if (mediaChunks.isEmpty()) {
pendingResetPositionUs = lastSeekPositionUs;
}
}
} else {
Log.w(TAG, "Ignoring attempt to cancel non-cancelable load.");
}
}
if (loadErrorAction == null) {
// The load was not cancelled. Either the load must be retried or the error propagated.
long retryDelayMs = loadErrorHandlingPolicy.getRetryDelayMsFor(loadErrorInfo);
loadErrorAction = retryDelayMs != C.TIME_UNSET ? Loader.createRetryAction(/* resetErrorCount= */
false, retryDelayMs) : Loader.DONT_RETRY_FATAL;
}
boolean canceled = !loadErrorAction.isRetry();
mediaSourceEventDispatcher.loadError(loadEventInfo, loadable.type, primaryTrackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, error, canceled);
if (canceled) {
loadingChunk = null;
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
callback.onContinueLoadingRequested(this);
}
return loadErrorAction;
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class TsExtractor method seek.
@Override
public void seek(long position, long timeUs) {
Assertions.checkState(mode != MODE_HLS);
int timestampAdjustersCount = timestampAdjusters.size();
for (int i = 0; i < timestampAdjustersCount; i++) {
TimestampAdjuster timestampAdjuster = timestampAdjusters.get(i);
// If the timestamp adjuster has not yet established a timestamp offset, we need to reset its
// expected first sample timestamp to be the new seek position. Without this, the timestamp
// adjuster would incorrectly establish its timestamp offset assuming that the first sample
// after this seek corresponds to the start of the stream (or a previous seek position, if
// there was one).
boolean resetTimestampAdjuster = timestampAdjuster.getTimestampOffsetUs() == C.TIME_UNSET;
if (!resetTimestampAdjuster) {
long adjusterFirstSampleTimestampUs = timestampAdjuster.getFirstSampleTimestampUs();
// Also reset the timestamp adjuster if its offset was calculated based on a non-zero
// position in the stream (other than the position being seeked to), since in this case the
// offset may not be accurate.
resetTimestampAdjuster = adjusterFirstSampleTimestampUs != C.TIME_UNSET && adjusterFirstSampleTimestampUs != 0 && adjusterFirstSampleTimestampUs != timeUs;
}
if (resetTimestampAdjuster) {
timestampAdjuster.reset(timeUs);
}
}
if (timeUs != 0 && tsBinarySearchSeeker != null) {
tsBinarySearchSeeker.setSeekTargetUs(timeUs);
}
tsPacketBuffer.reset(/* limit= */
0);
continuityCounters.clear();
for (int i = 0; i < tsPayloadReaders.size(); i++) {
tsPayloadReaders.valueAt(i).seek();
}
bytesSinceLastSync = 0;
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class WavHeaderReader method readFormat.
/**
* Reads and returns a {@code WavFormat}.
*
* @param input Input stream to read the WAV format from. The position should point to the byte
* following the ds64 chunk if present, or to the byte following the WAVE tag otherwise.
* @throws IOException If reading from the input fails.
* @return A new {@code WavFormat} read from {@code input}.
*/
public static WavFormat readFormat(ExtractorInput input) throws IOException {
// Allocate a scratch buffer large enough to store the format chunk.
ParsableByteArray scratch = new ParsableByteArray(16);
// Skip chunks until we find the format chunk.
ChunkHeader chunkHeader = skipToChunk(/* chunkId= */
WavUtil.FMT_FOURCC, input, scratch);
Assertions.checkState(chunkHeader.size >= 16);
input.peekFully(scratch.getData(), 0, 16);
scratch.setPosition(0);
int audioFormatType = scratch.readLittleEndianUnsignedShort();
int numChannels = scratch.readLittleEndianUnsignedShort();
int frameRateHz = scratch.readLittleEndianUnsignedIntToInt();
int averageBytesPerSecond = scratch.readLittleEndianUnsignedIntToInt();
int blockSize = scratch.readLittleEndianUnsignedShort();
int bitsPerSample = scratch.readLittleEndianUnsignedShort();
int bytesLeft = (int) chunkHeader.size - 16;
byte[] extraData;
if (bytesLeft > 0) {
extraData = new byte[bytesLeft];
input.peekFully(extraData, 0, bytesLeft);
} else {
extraData = Util.EMPTY_BYTE_ARRAY;
}
input.skipFully((int) (input.getPeekPosition() - input.getPosition()));
return new WavFormat(audioFormatType, numChannels, frameRateHz, averageBytesPerSecond, blockSize, bitsPerSample, extraData);
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class WebViewSubtitleOutput method updateWebView.
private void updateWebView() {
StringBuilder html = new StringBuilder();
html.append(Util.formatInvariant("<body><div style='" + "-webkit-user-select:none;" + "position:fixed;" + "top:0;" + "bottom:0;" + "left:0;" + "right:0;" + "color:%s;" + "font-size:%s;" + "line-height:%.2f;" + "text-shadow:%s;" + "'>", HtmlUtils.toCssRgba(style.foregroundColor), convertTextSizeToCss(defaultTextSizeType, defaultTextSize), CSS_LINE_HEIGHT, convertCaptionStyleToCssTextShadow(style)));
Map<String, String> cssRuleSets = new HashMap<>();
cssRuleSets.put(HtmlUtils.cssAllClassDescendantsSelector(DEFAULT_BACKGROUND_CSS_CLASS), Util.formatInvariant("background-color:%s;", HtmlUtils.toCssRgba(style.backgroundColor)));
for (int i = 0; i < textCues.size(); i++) {
Cue cue = textCues.get(i);
float positionPercent = (cue.position != Cue.DIMEN_UNSET) ? (cue.position * 100) : 50;
int positionAnchorTranslatePercent = anchorTypeToTranslatePercent(cue.positionAnchor);
String lineValue;
boolean lineMeasuredFromEnd = false;
int lineAnchorTranslatePercent = 0;
if (cue.line != Cue.DIMEN_UNSET) {
switch(cue.lineType) {
case Cue.LINE_TYPE_NUMBER:
if (cue.line >= 0) {
lineValue = Util.formatInvariant("%.2fem", cue.line * CSS_LINE_HEIGHT);
} else {
lineValue = Util.formatInvariant("%.2fem", (-cue.line - 1) * CSS_LINE_HEIGHT);
lineMeasuredFromEnd = true;
}
break;
case Cue.LINE_TYPE_FRACTION:
case Cue.TYPE_UNSET:
default:
lineValue = Util.formatInvariant("%.2f%%", cue.line * 100);
lineAnchorTranslatePercent = cue.verticalType == Cue.VERTICAL_TYPE_RL ? -anchorTypeToTranslatePercent(cue.lineAnchor) : anchorTypeToTranslatePercent(cue.lineAnchor);
}
} else {
lineValue = Util.formatInvariant("%.2f%%", (1.0f - bottomPaddingFraction) * 100);
lineAnchorTranslatePercent = -100;
}
String size = cue.size != Cue.DIMEN_UNSET ? Util.formatInvariant("%.2f%%", cue.size * 100) : "fit-content";
String textAlign = convertAlignmentToCss(cue.textAlignment);
String writingMode = convertVerticalTypeToCss(cue.verticalType);
String cueTextSizeCssPx = convertTextSizeToCss(cue.textSizeType, cue.textSize);
String windowCssColor = HtmlUtils.toCssRgba(cue.windowColorSet ? cue.windowColor : style.windowColor);
String positionProperty;
String lineProperty;
switch(cue.verticalType) {
case Cue.VERTICAL_TYPE_LR:
lineProperty = lineMeasuredFromEnd ? "right" : "left";
positionProperty = "top";
break;
case Cue.VERTICAL_TYPE_RL:
lineProperty = lineMeasuredFromEnd ? "left" : "right";
positionProperty = "top";
break;
case Cue.TYPE_UNSET:
default:
lineProperty = lineMeasuredFromEnd ? "bottom" : "top";
positionProperty = "left";
}
String sizeProperty;
int horizontalTranslatePercent;
int verticalTranslatePercent;
if (cue.verticalType == Cue.VERTICAL_TYPE_LR || cue.verticalType == Cue.VERTICAL_TYPE_RL) {
sizeProperty = "height";
horizontalTranslatePercent = lineAnchorTranslatePercent;
verticalTranslatePercent = positionAnchorTranslatePercent;
} else {
sizeProperty = "width";
horizontalTranslatePercent = positionAnchorTranslatePercent;
verticalTranslatePercent = lineAnchorTranslatePercent;
}
SpannedToHtmlConverter.HtmlAndCss htmlAndCss = SpannedToHtmlConverter.convert(cue.text, getContext().getResources().getDisplayMetrics().density);
for (String cssSelector : cssRuleSets.keySet()) {
@Nullable String previousCssDeclarationBlock = cssRuleSets.put(cssSelector, cssRuleSets.get(cssSelector));
Assertions.checkState(previousCssDeclarationBlock == null || previousCssDeclarationBlock.equals(cssRuleSets.get(cssSelector)));
}
html.append(Util.formatInvariant("<div style='" + "position:absolute;" + "z-index:%s;" + "%s:%.2f%%;" + "%s:%s;" + "%s:%s;" + "text-align:%s;" + "writing-mode:%s;" + "font-size:%s;" + "background-color:%s;" + "transform:translate(%s%%,%s%%)" + "%s;" + "'>", /* z-index */
i, positionProperty, positionPercent, lineProperty, lineValue, sizeProperty, size, textAlign, writingMode, cueTextSizeCssPx, windowCssColor, horizontalTranslatePercent, verticalTranslatePercent, getBlockShearTransformFunction(cue))).append(Util.formatInvariant("<span class='%s'>", DEFAULT_BACKGROUND_CSS_CLASS));
if (cue.multiRowAlignment != null) {
html.append(Util.formatInvariant("<span style='display:inline-block; text-align:%s;'>", convertAlignmentToCss(cue.multiRowAlignment))).append(htmlAndCss.html).append("</span>");
} else {
html.append(htmlAndCss.html);
}
html.append("</span>").append("</div>");
}
html.append("</div></body></html>");
StringBuilder htmlHead = new StringBuilder();
htmlHead.append("<html><head><style>");
for (String cssSelector : cssRuleSets.keySet()) {
htmlHead.append(cssSelector).append("{").append(cssRuleSets.get(cssSelector)).append("}");
}
htmlHead.append("</style></head>");
html.insert(0, htmlHead.toString());
webView.loadData(Base64.encodeToString(html.toString().getBytes(Charsets.UTF_8), Base64.NO_PADDING), "text/html", "base64");
}
Aggregations