use of com.google.android.exoplayer2.util.Assertions.checkNotNull in project ExoPlayer by google.
the class HlsMediaPeriod method getStreamKeys.
// TODO: When the multivariant playlist does not de-duplicate variants by URL and allows
// Renditions with null URLs, this method must be updated to calculate stream keys that are
// compatible with those that may already be persisted for offline.
@Override
public List<StreamKey> getStreamKeys(List<ExoTrackSelection> trackSelections) {
// See HlsMultivariantPlaylist.copy for interpretation of StreamKeys.
HlsMultivariantPlaylist multivariantPlaylist = Assertions.checkNotNull(playlistTracker.getMultivariantPlaylist());
boolean hasVariants = !multivariantPlaylist.variants.isEmpty();
int audioWrapperOffset = hasVariants ? 1 : 0;
// Subtitle sample stream wrappers are held last.
int subtitleWrapperOffset = sampleStreamWrappers.length - multivariantPlaylist.subtitles.size();
TrackGroupArray mainWrapperTrackGroups;
int mainWrapperPrimaryGroupIndex;
int[] mainWrapperVariantIndices;
if (hasVariants) {
HlsSampleStreamWrapper mainWrapper = sampleStreamWrappers[0];
mainWrapperVariantIndices = manifestUrlIndicesPerWrapper[0];
mainWrapperTrackGroups = mainWrapper.getTrackGroups();
mainWrapperPrimaryGroupIndex = mainWrapper.getPrimaryTrackGroupIndex();
} else {
mainWrapperVariantIndices = new int[0];
mainWrapperTrackGroups = TrackGroupArray.EMPTY;
mainWrapperPrimaryGroupIndex = 0;
}
List<StreamKey> streamKeys = new ArrayList<>();
boolean needsPrimaryTrackGroupSelection = false;
boolean hasPrimaryTrackGroupSelection = false;
for (ExoTrackSelection trackSelection : trackSelections) {
TrackGroup trackSelectionGroup = trackSelection.getTrackGroup();
int mainWrapperTrackGroupIndex = mainWrapperTrackGroups.indexOf(trackSelectionGroup);
if (mainWrapperTrackGroupIndex != C.INDEX_UNSET) {
if (mainWrapperTrackGroupIndex == mainWrapperPrimaryGroupIndex) {
// Primary group in main wrapper.
hasPrimaryTrackGroupSelection = true;
for (int i = 0; i < trackSelection.length(); i++) {
int variantIndex = mainWrapperVariantIndices[trackSelection.getIndexInTrackGroup(i)];
streamKeys.add(new StreamKey(HlsMultivariantPlaylist.GROUP_INDEX_VARIANT, variantIndex));
}
} else {
// Embedded group in main wrapper.
needsPrimaryTrackGroupSelection = true;
}
} else {
// Audio or subtitle group.
for (int i = audioWrapperOffset; i < sampleStreamWrappers.length; i++) {
TrackGroupArray wrapperTrackGroups = sampleStreamWrappers[i].getTrackGroups();
int selectedTrackGroupIndex = wrapperTrackGroups.indexOf(trackSelectionGroup);
if (selectedTrackGroupIndex != C.INDEX_UNSET) {
int groupIndexType = i < subtitleWrapperOffset ? HlsMultivariantPlaylist.GROUP_INDEX_AUDIO : HlsMultivariantPlaylist.GROUP_INDEX_SUBTITLE;
int[] selectedWrapperUrlIndices = manifestUrlIndicesPerWrapper[i];
for (int trackIndex = 0; trackIndex < trackSelection.length(); trackIndex++) {
int renditionIndex = selectedWrapperUrlIndices[trackSelection.getIndexInTrackGroup(trackIndex)];
streamKeys.add(new StreamKey(groupIndexType, renditionIndex));
}
break;
}
}
}
}
if (needsPrimaryTrackGroupSelection && !hasPrimaryTrackGroupSelection) {
// A track selection includes a variant-embedded track, but no variant is added yet. We use
// the valid variant with the lowest bitrate to reduce overhead.
int lowestBitrateIndex = mainWrapperVariantIndices[0];
int lowestBitrate = multivariantPlaylist.variants.get(mainWrapperVariantIndices[0]).format.bitrate;
for (int i = 1; i < mainWrapperVariantIndices.length; i++) {
int variantBitrate = multivariantPlaylist.variants.get(mainWrapperVariantIndices[i]).format.bitrate;
if (variantBitrate < lowestBitrate) {
lowestBitrate = variantBitrate;
lowestBitrateIndex = mainWrapperVariantIndices[i];
}
}
streamKeys.add(new StreamKey(HlsMultivariantPlaylist.GROUP_INDEX_VARIANT, lowestBitrateIndex));
}
return streamKeys;
}
use of com.google.android.exoplayer2.util.Assertions.checkNotNull in project ExoPlayer by google.
the class WebvttExtractor method processSample.
@RequiresNonNull("output")
private void processSample() throws ParserException {
ParsableByteArray webvttData = new ParsableByteArray(sampleData);
// Validate the first line of the header.
WebvttParserUtil.validateWebvttHeaderLine(webvttData);
// Defaults to use if the header doesn't contain an X-TIMESTAMP-MAP header.
long vttTimestampUs = 0;
long tsTimestampUs = 0;
// Parse the remainder of the header looking for X-TIMESTAMP-MAP.
for (String line = webvttData.readLine(); !TextUtils.isEmpty(line); line = webvttData.readLine()) {
if (line.startsWith("X-TIMESTAMP-MAP")) {
Matcher localTimestampMatcher = LOCAL_TIMESTAMP.matcher(line);
if (!localTimestampMatcher.find()) {
throw ParserException.createForMalformedContainer("X-TIMESTAMP-MAP doesn't contain local timestamp: " + line, /* cause= */
null);
}
Matcher mediaTimestampMatcher = MEDIA_TIMESTAMP.matcher(line);
if (!mediaTimestampMatcher.find()) {
throw ParserException.createForMalformedContainer("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line, /* cause= */
null);
}
vttTimestampUs = WebvttParserUtil.parseTimestampUs(Assertions.checkNotNull(localTimestampMatcher.group(1)));
tsTimestampUs = TimestampAdjuster.ptsToUs(Long.parseLong(Assertions.checkNotNull(mediaTimestampMatcher.group(1))));
}
}
// Find the first cue header and parse the start time.
Matcher cueHeaderMatcher = WebvttParserUtil.findNextCueHeader(webvttData);
if (cueHeaderMatcher == null) {
// No cues found. Don't output a sample, but still output a corresponding track.
buildTrackOutput(0);
return;
}
long firstCueTimeUs = WebvttParserUtil.parseTimestampUs(Assertions.checkNotNull(cueHeaderMatcher.group(1)));
long sampleTimeUs = timestampAdjuster.adjustTsTimestamp(TimestampAdjuster.usToWrappedPts(firstCueTimeUs + tsTimestampUs - vttTimestampUs));
long subsampleOffsetUs = sampleTimeUs - firstCueTimeUs;
// Output the track.
TrackOutput trackOutput = buildTrackOutput(subsampleOffsetUs);
// Output the sample.
sampleDataWrapper.reset(sampleData, sampleSize);
trackOutput.sampleData(sampleDataWrapper, sampleSize);
trackOutput.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
}
use of com.google.android.exoplayer2.util.Assertions.checkNotNull in project ExoPlayer by google.
the class DecoderVideoRenderer method onInputFormatChanged.
/**
* Called when a new format is read from the upstream source.
*
* @param formatHolder A {@link FormatHolder} that holds the new {@link Format}.
* @throws ExoPlaybackException If an error occurs (re-)initializing the decoder.
*/
@CallSuper
protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
waitingForFirstSampleInFormat = true;
Format newFormat = Assertions.checkNotNull(formatHolder.format);
setSourceDrmSession(formatHolder.drmSession);
Format oldFormat = inputFormat;
inputFormat = newFormat;
if (decoder == null) {
maybeInitDecoder();
eventDispatcher.inputFormatChanged(inputFormat, /* decoderReuseEvaluation= */
null);
return;
}
DecoderReuseEvaluation evaluation;
if (sourceDrmSession != decoderDrmSession) {
evaluation = new DecoderReuseEvaluation(decoder.getName(), oldFormat, newFormat, REUSE_RESULT_NO, DISCARD_REASON_DRM_SESSION_CHANGED);
} else {
evaluation = canReuseDecoder(decoder.getName(), oldFormat, newFormat);
}
if (evaluation.result == REUSE_RESULT_NO) {
if (decoderReceivedBuffers) {
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
} else {
// There aren't any final output buffers, so release the decoder immediately.
releaseDecoder();
maybeInitDecoder();
}
}
eventDispatcher.inputFormatChanged(inputFormat, evaluation);
}
use of com.google.android.exoplayer2.util.Assertions.checkNotNull in project ExoPlayer by google.
the class TtmlDecoderTest method getOnlyCueTextAtTimeUs.
private static Spanned getOnlyCueTextAtTimeUs(Subtitle subtitle, long timeUs) {
Cue cue = getOnlyCueAtTimeUs(subtitle, timeUs);
assertThat(cue.text).isInstanceOf(Spanned.class);
return (Spanned) Assertions.checkNotNull(cue.text);
}
use of com.google.android.exoplayer2.util.Assertions.checkNotNull in project ExoPlayer by google.
the class RepeatedTranscodeTransformationTest method repeatedTranscodeNoVideo_givesConsistentLengthOutput.
@Test
public void repeatedTranscodeNoVideo_givesConsistentLengthOutput() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
Transformer transformer = new Transformer.Builder(context).setRemoveVideo(true).setTransformationRequest(new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AMR_NB).build()).build();
Set<Long> differentOutputSizesBytes = new HashSet<>();
for (int i = 0; i < TRANSCODE_COUNT; i++) {
// Use a long video in case an error occurs a while after the start of the video.
AndroidTestUtil.TransformationResult result = runTransformer(context, /* testId= */
"repeatedTranscodeNoVideo_givesConsistentLengthOutput_" + i, transformer, AndroidTestUtil.REMOTE_MP4_10_SECONDS_URI_STRING, /* timeoutSeconds= */
120);
differentOutputSizesBytes.add(Assertions.checkNotNull(result.fileSizeBytes));
}
assertWithMessage("Different transcoding output sizes detected. Sizes: " + differentOutputSizesBytes).that(differentOutputSizesBytes.size()).isEqualTo(1);
}
Aggregations