Java Code Examples for com.google.android.exoplayer2.source.TrackGroupArray#EMPTY

The following examples show how to use com.google.android.exoplayer2.source.TrackGroupArray#EMPTY . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PlaybackInfo.java    From MediaSDK with Apache License 2.0 6 votes vote down vote up
/**
 * Creates empty dummy playback info which can be used for masking as long as no real playback
 * info is available.
 *
 * @param startPositionUs The start position at which playback should start, in microseconds.
 * @param emptyTrackSelectorResult An empty track selector result with null entries for each
 *     renderer.
 * @return A dummy playback info.
 */
public static PlaybackInfo createDummy(
    long startPositionUs, TrackSelectorResult emptyTrackSelectorResult) {
  return new PlaybackInfo(
      Timeline.EMPTY,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* contentPositionUs= */ C.TIME_UNSET,
      Player.STATE_IDLE,
      /* playbackError= */ null,
      /* isLoading= */ false,
      TrackGroupArray.EMPTY,
      emptyTrackSelectorResult,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 2
Source File: MediaPeriodHolder.java    From MediaSDK with Apache License 2.0 6 votes vote down vote up
/**
 * Creates a new holder with information required to play it as part of a timeline.
 *
 * @param rendererCapabilities The renderer capabilities.
 * @param rendererPositionOffsetUs The renderer time of the start of the period, in microseconds.
 * @param trackSelector The track selector.
 * @param allocator The allocator.
 * @param mediaSource The media source that produced the media period.
 * @param info Information used to identify this media period in its timeline period.
 * @param emptyTrackSelectorResult A {@link TrackSelectorResult} with empty selections for each
 *     renderer.
 */
public MediaPeriodHolder(
    RendererCapabilities[] rendererCapabilities,
    long rendererPositionOffsetUs,
    TrackSelector trackSelector,
    Allocator allocator,
    MediaSource mediaSource,
    MediaPeriodInfo info,
    TrackSelectorResult emptyTrackSelectorResult) {
  this.rendererCapabilities = rendererCapabilities;
  this.rendererPositionOffsetUs = rendererPositionOffsetUs;
  this.trackSelector = trackSelector;
  this.mediaSource = mediaSource;
  this.uid = info.id.periodUid;
  this.info = info;
  this.trackGroups = TrackGroupArray.EMPTY;
  this.trackSelectorResult = emptyTrackSelectorResult;
  sampleStreams = new SampleStream[rendererCapabilities.length];
  mayRetainStreamFlags = new boolean[rendererCapabilities.length];
  mediaPeriod =
      createMediaPeriod(
          info.id, mediaSource, allocator, info.startPositionUs, info.endPositionUs);
}
 
Example 3
Source File: ExoPlayerImpl.java    From K-Sonic with MIT License 6 votes vote down vote up
/**
 * Constructs an instance. Must be called from a thread that has an associated {@link Looper}.
 *
 * @param renderers The {@link Renderer}s that will be used by the instance.
 * @param trackSelector The {@link TrackSelector} that will be used by the instance.
 * @param loadControl The {@link LoadControl} that will be used by the instance.
 */
@SuppressLint("HandlerLeak")
public ExoPlayerImpl(Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl) {
  Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION + " [" + Util.DEVICE_DEBUG_INFO + "]");
  Assertions.checkState(renderers.length > 0);
  this.renderers = Assertions.checkNotNull(renderers);
  this.trackSelector = Assertions.checkNotNull(trackSelector);
  this.playWhenReady = false;
  this.playbackState = STATE_IDLE;
  this.listeners = new CopyOnWriteArraySet<>();
  emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]);
  timeline = Timeline.EMPTY;
  window = new Timeline.Window();
  period = new Timeline.Period();
  trackGroups = TrackGroupArray.EMPTY;
  trackSelections = emptyTrackSelections;
  eventHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      ExoPlayerImpl.this.handleEvent(msg);
    }
  };
  playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0, 0);
  internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, loadControl, playWhenReady,
      eventHandler, playbackInfo, this);
}
 
Example 4
Source File: PlaybackInfo.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Creates empty dummy playback info which can be used for masking as long as no real playback
 * info is available.
 *
 * @param startPositionUs The start position at which playback should start, in microseconds.
 * @param emptyTrackSelectorResult An empty track selector result with null entries for each
 *     renderer.
 * @return A dummy playback info.
 */
public static PlaybackInfo createDummy(
    long startPositionUs, TrackSelectorResult emptyTrackSelectorResult) {
  return new PlaybackInfo(
      Timeline.EMPTY,
      /* manifest= */ null,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* contentPositionUs =*/ C.TIME_UNSET,
      Player.STATE_IDLE,
      /* isLoading= */ false,
      TrackGroupArray.EMPTY,
      emptyTrackSelectorResult,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 5
Source File: ExoPlayerImpl.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
private PlaybackInfo getResetPlaybackInfo(
    boolean resetPosition, boolean resetState, int playbackState) {
  if (resetPosition) {
    maskingWindowIndex = 0;
    maskingPeriodIndex = 0;
    maskingWindowPositionMs = 0;
  } else {
    maskingWindowIndex = getCurrentWindowIndex();
    maskingPeriodIndex = getCurrentPeriodIndex();
    maskingWindowPositionMs = getCurrentPosition();
  }
  return new PlaybackInfo(
      resetState ? Timeline.EMPTY : playbackInfo.timeline,
      resetState ? null : playbackInfo.manifest,
      playbackInfo.periodId,
      playbackInfo.startPositionUs,
      playbackInfo.contentPositionUs,
      playbackState,
      /* isLoading= */ false,
      resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
      resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
      playbackInfo.periodId,
      playbackInfo.startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      playbackInfo.startPositionUs);
}
 
Example 6
Source File: HlsDownloadHelper.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
@Override
public TrackGroupArray getTrackGroups(int periodIndex) {
  Assertions.checkNotNull(playlist);
  if (playlist instanceof HlsMediaPlaylist) {
    renditionGroups = new int[0];
    return TrackGroupArray.EMPTY;
  }
  // TODO: Generate track groups as in playback. Reverse the mapping in getDownloadAction.
  HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
  TrackGroup[] trackGroups = new TrackGroup[3];
  renditionGroups = new int[3];
  int trackGroupIndex = 0;
  if (!masterPlaylist.variants.isEmpty()) {
    renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_VARIANT;
    trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.variants));
  }
  if (!masterPlaylist.audios.isEmpty()) {
    renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_AUDIO;
    trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.audios));
  }
  if (!masterPlaylist.subtitles.isEmpty()) {
    renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_SUBTITLE;
    trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.subtitles));
  }
  return new TrackGroupArray(Arrays.copyOf(trackGroups, trackGroupIndex));
}
 
Example 7
Source File: PlaybackInfo.java    From Telegram with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Creates empty dummy playback info which can be used for masking as long as no real playback
 * info is available.
 *
 * @param startPositionUs The start position at which playback should start, in microseconds.
 * @param emptyTrackSelectorResult An empty track selector result with null entries for each
 *     renderer.
 * @return A dummy playback info.
 */
public static PlaybackInfo createDummy(
    long startPositionUs, TrackSelectorResult emptyTrackSelectorResult) {
  return new PlaybackInfo(
      Timeline.EMPTY,
      /* manifest= */ null,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* contentPositionUs= */ C.TIME_UNSET,
      Player.STATE_IDLE,
      /* isLoading= */ false,
      TrackGroupArray.EMPTY,
      emptyTrackSelectorResult,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 8
Source File: ExoPlayerImpl.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
private PlaybackInfo getResetPlaybackInfo(
    boolean resetPosition, boolean resetState, int playbackState) {
  if (resetPosition) {
    maskingWindowIndex = 0;
    maskingPeriodIndex = 0;
    maskingWindowPositionMs = 0;
  } else {
    maskingWindowIndex = getCurrentWindowIndex();
    maskingPeriodIndex = getCurrentPeriodIndex();
    maskingWindowPositionMs = getCurrentPosition();
  }
  return new PlaybackInfo(
      resetState ? Timeline.EMPTY : playbackInfo.timeline,
      resetState ? null : playbackInfo.manifest,
      playbackInfo.periodId,
      playbackInfo.startPositionUs,
      playbackInfo.contentPositionUs,
      playbackState,
      /* isLoading= */ false,
      resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
      resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
      playbackInfo.periodId,
      playbackInfo.startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      playbackInfo.startPositionUs);
}
 
Example 9
Source File: PlaybackInfo.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Creates empty dummy playback info which can be used for masking as long as no real playback
 * info is available.
 *
 * @param startPositionUs The start position at which playback should start, in microseconds.
 * @param emptyTrackSelectorResult An empty track selector result with null entries for each
 *     renderer.
 * @return A dummy playback info.
 */
public static PlaybackInfo createDummy(
    long startPositionUs, TrackSelectorResult emptyTrackSelectorResult) {
  return new PlaybackInfo(
      Timeline.EMPTY,
      /* manifest= */ null,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* contentPositionUs =*/ C.TIME_UNSET,
      Player.STATE_IDLE,
      /* isLoading= */ false,
      TrackGroupArray.EMPTY,
      emptyTrackSelectorResult,
      DUMMY_MEDIA_PERIOD_ID,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 10
Source File: ExoPlayerImpl.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
private PlaybackInfo getResetPlaybackInfo(
    boolean resetPosition, boolean resetState, int playbackState) {
  if (resetPosition) {
    maskingWindowIndex = 0;
    maskingPeriodIndex = 0;
    maskingWindowPositionMs = 0;
  } else {
    maskingWindowIndex = getCurrentWindowIndex();
    maskingPeriodIndex = getCurrentPeriodIndex();
    maskingWindowPositionMs = getCurrentPosition();
  }
  // Also reset period-based PlaybackInfo positions if resetting the state.
  resetPosition = resetPosition || resetState;
  MediaPeriodId mediaPeriodId =
      resetPosition
          ? playbackInfo.getDummyFirstMediaPeriodId(shuffleModeEnabled, window)
          : playbackInfo.periodId;
  long startPositionUs = resetPosition ? 0 : playbackInfo.positionUs;
  long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs;
  return new PlaybackInfo(
      resetState ? Timeline.EMPTY : playbackInfo.timeline,
      resetState ? null : playbackInfo.manifest,
      mediaPeriodId,
      startPositionUs,
      contentPositionUs,
      playbackState,
      /* isLoading= */ false,
      resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
      resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
      mediaPeriodId,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 11
Source File: ExoPlayerImpl.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
private PlaybackInfo getResetPlaybackInfo(
    boolean resetPosition,
    boolean resetState,
    boolean resetError,
    @State int playbackState) {
  if (resetPosition) {
    maskingWindowIndex = 0;
    maskingPeriodIndex = 0;
    maskingWindowPositionMs = 0;
  } else {
    maskingWindowIndex = getCurrentWindowIndex();
    maskingPeriodIndex = getCurrentPeriodIndex();
    maskingWindowPositionMs = getCurrentPosition();
  }
  // Also reset period-based PlaybackInfo positions if resetting the state.
  resetPosition = resetPosition || resetState;
  MediaPeriodId mediaPeriodId =
      resetPosition
          ? playbackInfo.getDummyFirstMediaPeriodId(shuffleModeEnabled, window, period)
          : playbackInfo.periodId;
  long startPositionUs = resetPosition ? 0 : playbackInfo.positionUs;
  long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs;
  return new PlaybackInfo(
      resetState ? Timeline.EMPTY : playbackInfo.timeline,
      mediaPeriodId,
      startPositionUs,
      contentPositionUs,
      playbackState,
      resetError ? null : playbackInfo.playbackError,
      /* isLoading= */ false,
      resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
      resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
      mediaPeriodId,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 12
Source File: ExoPlayerImpl.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
private PlaybackInfo getResetPlaybackInfo(
    boolean resetPosition, boolean resetState, int playbackState) {
  if (resetPosition) {
    maskingWindowIndex = 0;
    maskingPeriodIndex = 0;
    maskingWindowPositionMs = 0;
  } else {
    maskingWindowIndex = getCurrentWindowIndex();
    maskingPeriodIndex = getCurrentPeriodIndex();
    maskingWindowPositionMs = getCurrentPosition();
  }
  // Also reset period-based PlaybackInfo positions if resetting the state.
  resetPosition = resetPosition || resetState;
  MediaPeriodId mediaPeriodId =
      resetPosition
          ? playbackInfo.getDummyFirstMediaPeriodId(shuffleModeEnabled, window)
          : playbackInfo.periodId;
  long startPositionUs = resetPosition ? 0 : playbackInfo.positionUs;
  long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs;
  return new PlaybackInfo(
      resetState ? Timeline.EMPTY : playbackInfo.timeline,
      resetState ? null : playbackInfo.manifest,
      mediaPeriodId,
      startPositionUs,
      contentPositionUs,
      playbackState,
      /* isLoading= */ false,
      resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
      resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
      mediaPeriodId,
      startPositionUs,
      /* totalBufferedDurationUs= */ 0,
      startPositionUs);
}
 
Example 13
Source File: HlsSampleStreamWrapper.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Builds tracks that are exposed by this {@link HlsSampleStreamWrapper} instance, as well as
 * internal data-structures required for operation.
 *
 * <p>Tracks in HLS are complicated. A HLS master playlist contains a number of "variants". Each
 * variant stream typically contains muxed video, audio and (possibly) additional audio, metadata
 * and caption tracks. We wish to allow the user to select between an adaptive track that spans
 * all variants, as well as each individual variant. If multiple audio tracks are present within
 * each variant then we wish to allow the user to select between those also.
 *
 * <p>To do this, tracks are constructed as follows. The {@link HlsChunkSource} exposes (N+1)
 * tracks, where N is the number of variants defined in the HLS master playlist. These consist of
 * one adaptive track defined to span all variants and a track for each individual variant. The
 * adaptive track is initially selected. The extractor is then prepared to discover the tracks
 * inside of each variant stream. The two sets of tracks are then combined by this method to
 * create a third set, which is the set exposed by this {@link HlsSampleStreamWrapper}:
 *
 * <ul>
 *   <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
 *       present then it is always the primary type. If not, audio is the primary type if present.
 *       Else text is the primary type if present. Else there is no primary type.
 *   <li>If there is exactly one extractor track of the primary type, it's expanded into (N+1)
 *       exposed tracks, all of which correspond to the primary extractor track and each of which
 *       corresponds to a different chunk source track. Selecting one of these tracks has the
 *       effect of switching the selected track on the chunk source.
 *   <li>All other extractor tracks are exposed directly. Selecting one of these tracks has the
 *       effect of selecting an extractor track, leaving the selected track on the chunk source
 *       unchanged.
 * </ul>
 */
private void buildTracksFromSampleStreams() {
  // Iterate through the extractor tracks to discover the "primary" track type, and the index
  // of the single track of this type.
  int primaryExtractorTrackType = C.TRACK_TYPE_NONE;
  int primaryExtractorTrackIndex = C.INDEX_UNSET;
  int extractorTrackCount = sampleQueues.length;
  for (int i = 0; i < extractorTrackCount; i++) {
    String sampleMimeType = sampleQueues[i].getUpstreamFormat().sampleMimeType;
    int trackType;
    if (MimeTypes.isVideo(sampleMimeType)) {
      trackType = C.TRACK_TYPE_VIDEO;
    } else if (MimeTypes.isAudio(sampleMimeType)) {
      trackType = C.TRACK_TYPE_AUDIO;
    } else if (MimeTypes.isText(sampleMimeType)) {
      trackType = C.TRACK_TYPE_TEXT;
    } else {
      trackType = C.TRACK_TYPE_NONE;
    }
    if (getTrackTypeScore(trackType) > getTrackTypeScore(primaryExtractorTrackType)) {
      primaryExtractorTrackType = trackType;
      primaryExtractorTrackIndex = i;
    } else if (trackType == primaryExtractorTrackType
        && primaryExtractorTrackIndex != C.INDEX_UNSET) {
      // We have multiple tracks of the primary type. We only want an index if there only exists a
      // single track of the primary type, so unset the index again.
      primaryExtractorTrackIndex = C.INDEX_UNSET;
    }
  }

  TrackGroup chunkSourceTrackGroup = chunkSource.getTrackGroup();
  int chunkSourceTrackCount = chunkSourceTrackGroup.length;

  // Instantiate the necessary internal data-structures.
  primaryTrackGroupIndex = C.INDEX_UNSET;
  trackGroupToSampleQueueIndex = new int[extractorTrackCount];
  for (int i = 0; i < extractorTrackCount; i++) {
    trackGroupToSampleQueueIndex[i] = i;
  }

  // Construct the set of exposed track groups.
  TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
  for (int i = 0; i < extractorTrackCount; i++) {
    Format sampleFormat = sampleQueues[i].getUpstreamFormat();
    if (i == primaryExtractorTrackIndex) {
      Format[] formats = new Format[chunkSourceTrackCount];
      if (chunkSourceTrackCount == 1) {
        formats[0] = sampleFormat.copyWithManifestFormatInfo(chunkSourceTrackGroup.getFormat(0));
      } else {
        for (int j = 0; j < chunkSourceTrackCount; j++) {
          formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat, true);
        }
      }
      trackGroups[i] = new TrackGroup(formats);
      primaryTrackGroupIndex = i;
    } else {
      Format trackFormat =
          primaryExtractorTrackType == C.TRACK_TYPE_VIDEO
                  && MimeTypes.isAudio(sampleFormat.sampleMimeType)
              ? muxedAudioFormat
              : null;
      trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat, false));
    }
  }
  this.trackGroups = new TrackGroupArray(trackGroups);
  Assertions.checkState(optionalTrackGroups == null);
  optionalTrackGroups = TrackGroupArray.EMPTY;
}
 
Example 14
Source File: HlsMediaPeriod.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
@Override
public List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) {
  // See HlsMasterPlaylist.copy for interpretation of StreamKeys.
  HlsMasterPlaylist masterPlaylist = Assertions.checkNotNull(playlistTracker.getMasterPlaylist());
  boolean hasVariants = !masterPlaylist.variants.isEmpty();
  int audioWrapperOffset = hasVariants ? 1 : 0;
  // Subtitle sample stream wrappers are held last.
  int subtitleWrapperOffset = sampleStreamWrappers.length - masterPlaylist.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 (TrackSelection 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(HlsMasterPlaylist.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
                  ? HlsMasterPlaylist.GROUP_INDEX_AUDIO
                  : HlsMasterPlaylist.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 = masterPlaylist.variants.get(mainWrapperVariantIndices[0]).format.bitrate;
    for (int i = 1; i < mainWrapperVariantIndices.length; i++) {
      int variantBitrate =
          masterPlaylist.variants.get(mainWrapperVariantIndices[i]).format.bitrate;
      if (variantBitrate < lowestBitrate) {
        lowestBitrate = variantBitrate;
        lowestBitrateIndex = mainWrapperVariantIndices[i];
      }
    }
    streamKeys.add(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, lowestBitrateIndex));
  }
  return streamKeys;
}
 
Example 15
Source File: ExoPlayerTrackSelector.java    From no-player with Apache License 2.0 4 votes vote down vote up
TrackGroupArray trackGroups(TrackType trackType, RendererTypeRequester rendererTypeRequester) {
    Optional<Integer> audioRendererIndex = rendererTrackIndexExtractor.extract(trackType, mappedTrackInfoLength(), rendererTypeRequester);
    return audioRendererIndex.isAbsent() ? TrackGroupArray.EMPTY : trackInfo().getTrackGroups(audioRendererIndex.get());
}
 
Example 16
Source File: ProgressiveDownloadHelper.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
@Override
public TrackGroupArray getTrackGroups(int periodIndex) {
  return TrackGroupArray.EMPTY;
}
 
Example 17
Source File: ExoPlayerImplInternal.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
private void resetInternal(
    boolean releaseMediaSource, boolean resetPosition, boolean resetState) {
  handler.removeMessages(MSG_DO_SOME_WORK);
  rebuffering = false;
  mediaClock.stop();
  rendererPositionUs = 0;
  for (Renderer renderer : enabledRenderers) {
    try {
      disableRenderer(renderer);
    } catch (ExoPlaybackException | RuntimeException e) {
      // There's nothing we can do.
      Log.e(TAG, "Stop failed.", e);
    }
  }
  enabledRenderers = new Renderer[0];
  queue.clear(/* keepFrontPeriodUid= */ !resetPosition);
  setIsLoading(false);
  if (resetPosition) {
    pendingInitialSeekPosition = null;
  }
  if (resetState) {
    queue.setTimeline(Timeline.EMPTY);
    for (PendingMessageInfo pendingMessageInfo : pendingMessages) {
      pendingMessageInfo.message.markAsProcessed(/* isDelivered= */ false);
    }
    pendingMessages.clear();
    nextPendingMessageIndex = 0;
  }
  // Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored.
  MediaPeriodId mediaPeriodId = resetPosition ? getFirstMediaPeriodId() : playbackInfo.periodId;
  long startPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.positionUs;
  long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs;
  playbackInfo =
      new PlaybackInfo(
          resetState ? Timeline.EMPTY : playbackInfo.timeline,
          resetState ? null : playbackInfo.manifest,
          mediaPeriodId,
          startPositionUs,
          contentPositionUs,
          playbackInfo.playbackState,
          /* isLoading= */ false,
          resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
          resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
          mediaPeriodId,
          startPositionUs,
          /* totalBufferedDurationUs= */ 0,
          startPositionUs);
  if (releaseMediaSource) {
    if (mediaSource != null) {
      mediaSource.releaseSource(/* listener= */ this);
      mediaSource = null;
    }
  }
}
 
Example 18
Source File: HlsSampleStreamWrapper.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Builds tracks that are exposed by this {@link HlsSampleStreamWrapper} instance, as well as
 * internal data-structures required for operation.
 *
 * <p>Tracks in HLS are complicated. A HLS master playlist contains a number of "variants". Each
 * variant stream typically contains muxed video, audio and (possibly) additional audio, metadata
 * and caption tracks. We wish to allow the user to select between an adaptive track that spans
 * all variants, as well as each individual variant. If multiple audio tracks are present within
 * each variant then we wish to allow the user to select between those also.
 *
 * <p>To do this, tracks are constructed as follows. The {@link HlsChunkSource} exposes (N+1)
 * tracks, where N is the number of variants defined in the HLS master playlist. These consist of
 * one adaptive track defined to span all variants and a track for each individual variant. The
 * adaptive track is initially selected. The extractor is then prepared to discover the tracks
 * inside of each variant stream. The two sets of tracks are then combined by this method to
 * create a third set, which is the set exposed by this {@link HlsSampleStreamWrapper}:
 *
 * <ul>
 *   <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
 *       present then it is always the primary type. If not, audio is the primary type if present.
 *       Else text is the primary type if present. Else there is no primary type.
 *   <li>If there is exactly one extractor track of the primary type, it's expanded into (N+1)
 *       exposed tracks, all of which correspond to the primary extractor track and each of which
 *       corresponds to a different chunk source track. Selecting one of these tracks has the
 *       effect of switching the selected track on the chunk source.
 *   <li>All other extractor tracks are exposed directly. Selecting one of these tracks has the
 *       effect of selecting an extractor track, leaving the selected track on the chunk source
 *       unchanged.
 * </ul>
 */
private void buildTracksFromSampleStreams() {
  // Iterate through the extractor tracks to discover the "primary" track type, and the index
  // of the single track of this type.
  int primaryExtractorTrackType = C.TRACK_TYPE_NONE;
  int primaryExtractorTrackIndex = C.INDEX_UNSET;
  int extractorTrackCount = sampleQueues.length;
  for (int i = 0; i < extractorTrackCount; i++) {
    String sampleMimeType = sampleQueues[i].getUpstreamFormat().sampleMimeType;
    int trackType;
    if (MimeTypes.isVideo(sampleMimeType)) {
      trackType = C.TRACK_TYPE_VIDEO;
    } else if (MimeTypes.isAudio(sampleMimeType)) {
      trackType = C.TRACK_TYPE_AUDIO;
    } else if (MimeTypes.isText(sampleMimeType)) {
      trackType = C.TRACK_TYPE_TEXT;
    } else {
      trackType = C.TRACK_TYPE_NONE;
    }
    if (getTrackTypeScore(trackType) > getTrackTypeScore(primaryExtractorTrackType)) {
      primaryExtractorTrackType = trackType;
      primaryExtractorTrackIndex = i;
    } else if (trackType == primaryExtractorTrackType
        && primaryExtractorTrackIndex != C.INDEX_UNSET) {
      // We have multiple tracks of the primary type. We only want an index if there only exists a
      // single track of the primary type, so unset the index again.
      primaryExtractorTrackIndex = C.INDEX_UNSET;
    }
  }

  TrackGroup chunkSourceTrackGroup = chunkSource.getTrackGroup();
  int chunkSourceTrackCount = chunkSourceTrackGroup.length;

  // Instantiate the necessary internal data-structures.
  primaryTrackGroupIndex = C.INDEX_UNSET;
  trackGroupToSampleQueueIndex = new int[extractorTrackCount];
  for (int i = 0; i < extractorTrackCount; i++) {
    trackGroupToSampleQueueIndex[i] = i;
  }

  // Construct the set of exposed track groups.
  TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
  for (int i = 0; i < extractorTrackCount; i++) {
    Format sampleFormat = sampleQueues[i].getUpstreamFormat();
    if (i == primaryExtractorTrackIndex) {
      Format[] formats = new Format[chunkSourceTrackCount];
      if (chunkSourceTrackCount == 1) {
        formats[0] = sampleFormat.copyWithManifestFormatInfo(chunkSourceTrackGroup.getFormat(0));
      } else {
        for (int j = 0; j < chunkSourceTrackCount; j++) {
          formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat, true);
        }
      }
      trackGroups[i] = new TrackGroup(formats);
      primaryTrackGroupIndex = i;
    } else {
      Format trackFormat =
          primaryExtractorTrackType == C.TRACK_TYPE_VIDEO
                  && MimeTypes.isAudio(sampleFormat.sampleMimeType)
              ? muxedAudioFormat
              : null;
      trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat, false));
    }
  }
  this.trackGroups = new TrackGroupArray(trackGroups);
  Assertions.checkState(optionalTrackGroups == null);
  optionalTrackGroups = TrackGroupArray.EMPTY;
}
 
Example 19
Source File: HlsMediaPeriod.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
@Override
public List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) {
  // See HlsMasterPlaylist.copy for interpretation of StreamKeys.
  HlsMasterPlaylist masterPlaylist = Assertions.checkNotNull(playlistTracker.getMasterPlaylist());
  boolean hasVariants = !masterPlaylist.variants.isEmpty();
  int audioWrapperOffset = hasVariants ? 1 : 0;
  // Subtitle sample stream wrappers are held last.
  int subtitleWrapperOffset = sampleStreamWrappers.length - masterPlaylist.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 (TrackSelection 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(HlsMasterPlaylist.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
                  ? HlsMasterPlaylist.GROUP_INDEX_AUDIO
                  : HlsMasterPlaylist.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 = masterPlaylist.variants.get(mainWrapperVariantIndices[0]).format.bitrate;
    for (int i = 1; i < mainWrapperVariantIndices.length; i++) {
      int variantBitrate =
          masterPlaylist.variants.get(mainWrapperVariantIndices[i]).format.bitrate;
      if (variantBitrate < lowestBitrate) {
        lowestBitrate = variantBitrate;
        lowestBitrateIndex = mainWrapperVariantIndices[i];
      }
    }
    streamKeys.add(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, lowestBitrateIndex));
  }
  return streamKeys;
}
 
Example 20
Source File: ExoPlayerImplInternal.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
private void resetInternal(
    boolean releaseMediaSource, boolean resetPosition, boolean resetState) {
  handler.removeMessages(MSG_DO_SOME_WORK);
  rebuffering = false;
  mediaClock.stop();
  rendererPositionUs = 0;
  for (Renderer renderer : enabledRenderers) {
    try {
      disableRenderer(renderer);
    } catch (ExoPlaybackException | RuntimeException e) {
      // There's nothing we can do.
      Log.e(TAG, "Stop failed.", e);
    }
  }
  enabledRenderers = new Renderer[0];
  queue.clear(/* keepFrontPeriodUid= */ !resetPosition);
  setIsLoading(false);
  if (resetPosition) {
    pendingInitialSeekPosition = null;
  }
  if (resetState) {
    queue.setTimeline(Timeline.EMPTY);
    for (PendingMessageInfo pendingMessageInfo : pendingMessages) {
      pendingMessageInfo.message.markAsProcessed(/* isDelivered= */ false);
    }
    pendingMessages.clear();
    nextPendingMessageIndex = 0;
  }
  // Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored.
  MediaPeriodId mediaPeriodId = resetPosition ? getFirstMediaPeriodId() : playbackInfo.periodId;
  long startPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.positionUs;
  long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs;
  playbackInfo =
      new PlaybackInfo(
          resetState ? Timeline.EMPTY : playbackInfo.timeline,
          resetState ? null : playbackInfo.manifest,
          mediaPeriodId,
          startPositionUs,
          contentPositionUs,
          playbackInfo.playbackState,
          /* isLoading= */ false,
          resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
          resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
          mediaPeriodId,
          startPositionUs,
          /* totalBufferedDurationUs= */ 0,
          startPositionUs);
  if (releaseMediaSource) {
    if (mediaSource != null) {
      mediaSource.releaseSource(/* listener= */ this);
      mediaSource = null;
    }
  }
}