use of org.jellyfin.apiclient.model.entities.MediaStream in project jellyfin-androidtv by jellyfin.
the class VideoManager method setVideoTrack.
public void setVideoTrack(MediaSourceInfo mediaSource) {
if (!nativeMode && mediaSource != null && mediaSource.getMediaStreams() != null) {
for (MediaStream stream : mediaSource.getMediaStreams()) {
if (stream.getType() == MediaStreamType.Video && stream.getIndex() >= 0) {
Timber.d("Setting video index to: %d", stream.getIndex());
mVlcPlayer.setVideoTrack(stream.getIndex());
return;
}
}
}
}
use of org.jellyfin.apiclient.model.entities.MediaStream in project jellyfin-androidtv by jellyfin.
the class VideoManager method setExoPlayerTrack.
public boolean setExoPlayerTrack(int index, @Nullable MediaStreamType streamType, @Nullable List<MediaStream> allStreams) {
if (!nativeMode || !isInitialized() || allStreams == null || streamType != MediaStreamType.Subtitle && streamType != MediaStreamType.Audio)
return false;
int chosenTrackType = streamType == MediaStreamType.Subtitle ? C.TRACK_TYPE_TEXT : C.TRACK_TYPE_AUDIO;
MediaStream candidate = allStreams.get(index);
if (candidate.getIsExternal() || candidate.getType() != streamType)
return false;
int exoTrackID = offsetStreamIndex(index, false, allStreams);
if (exoTrackID < 0)
return false;
// print the streams for debugging
for (MediaStream stream : allStreams) {
Timber.d("MediaStream track %s type %s label %s codec %s isExternal %s", stream.getIndex(), stream.getType(), stream.getTitle(), stream.getCodec(), stream.getIsExternal());
}
// design choices for exoplayer track selection overrides:
// * build upon the prior parameters so we can mix overrides of different track types without erasing priors
//
// * for subtitles (not currently used) - use setDisabledTrackTypes to disable or enable exoplayer handing subtitles
// if we want most formats to be handled by the external subtitle handler (which has adjustable size, background), we leave sub track selection disabled
// if we decide to use exoplayer to render a specific subtitle format, allow subtitle track selection and restrict selection to the chosen group
TracksInfo exoTracks = mExoPlayer.getCurrentTracksInfo();
TrackGroup matchedGroup = null;
for (TracksInfo.TrackGroupInfo groupInfo : exoTracks.getTrackGroupInfos()) {
// Group level information.
@C.TrackType int trackType = groupInfo.getTrackType();
TrackGroup group = groupInfo.getTrackGroup();
for (int i = 0; i < group.length; i++) {
// Individual track information.
boolean isSupported = groupInfo.isTrackSupported(i);
boolean isSelected = groupInfo.isTrackSelected(i);
Format trackFormat = group.getFormat(i);
Timber.d("track %s group %s/%s trackType %s label %s mime %s isSelected %s isSupported %s", trackFormat.id, i + 1, group.length, trackType, trackFormat.label, trackFormat.sampleMimeType, isSelected, isSupported);
if (trackType != chosenTrackType || trackFormat.id == null)
continue;
int id;
try {
id = Integer.parseInt(trackFormat.id);
if (id != exoTrackID)
continue;
} catch (NumberFormatException e) {
Timber.d("failed to parse track ID [%s]", trackFormat.id);
continue;
}
if (groupInfo.isTrackSelected(i) || !groupInfo.isTrackSupported(i)) {
Timber.d("track is %s", groupInfo.isTrackSelected(i) ? "already selected" : "not compatible");
return false;
}
Timber.d("matched exoplayer track %s to mediaStream track %s", trackFormat.id, index);
matchedGroup = group;
}
}
if (matchedGroup == null)
return false;
try {
TrackSelectionOverrides overrides = mExoPlayer.getTrackSelectionParameters().trackSelectionOverrides.buildUpon().setOverrideForType(new TrackSelectionOverrides.TrackSelectionOverride(matchedGroup)).build();
TrackSelectionParameters.Builder mExoPlayerSelectionParams = mExoPlayer.getTrackSelectionParameters().buildUpon();
if (streamType == MediaStreamType.Subtitle)
mExoPlayerSelectionParams.setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_NONE));
mExoPlayerSelectionParams.setTrackSelectionOverrides(overrides);
mExoPlayer.setTrackSelectionParameters(mExoPlayerSelectionParams.build());
} catch (Exception e) {
Timber.d("Error setting track selection");
return false;
}
return true;
}
use of org.jellyfin.apiclient.model.entities.MediaStream in project jellyfin-androidtv by jellyfin.
the class FullDetailsActivity method addInfoRows.
private void addInfoRows(ArrayObjectAdapter adapter) {
if (KoinJavaComponent.<UserPreferences>get(UserPreferences.class).get(UserPreferences.Companion.getDebuggingEnabled()) && mBaseItem.getMediaSources() != null) {
for (MediaSourceInfo ms : mBaseItem.getMediaSources()) {
if (ms.getMediaStreams() != null && ms.getMediaStreams().size() > 0) {
HeaderItem header = new HeaderItem("Media Details" + (ms.getContainer() != null ? " (" + ms.getContainer() + ")" : ""));
ArrayObjectAdapter infoAdapter = new ArrayObjectAdapter(new InfoCardPresenter());
for (MediaStream stream : ms.getMediaStreams()) {
infoAdapter.add(stream);
}
adapter.add(new ListRow(header, infoAdapter));
}
}
}
}
use of org.jellyfin.apiclient.model.entities.MediaStream in project jellyfin-androidtv by jellyfin.
the class PlaybackController method switchSubtitleStream.
public void switchSubtitleStream(int index) {
if (!hasInitializedVideoManager())
return;
// get current timestamp first
refreshCurrentPosition();
Timber.d("Setting subtitle index to: %d", index);
// clear subtitles first
if (mFragment != null)
mFragment.addManualSubtitles(null);
mVideoManager.disableSubs();
// clear the default in case there's an error loading the subtitles
mDefaultSubIndex = -1;
// restart playback if turning off burnt-in subtitles
if (index < 0) {
mCurrentOptions.setSubtitleStreamIndex(-1);
if (burningSubs) {
stop();
play(mCurrentPosition, -1);
}
return;
}
MediaStream stream = StreamHelper.getMediaStream(getCurrentMediaSource(), index);
if (stream == null) {
if (mFragment != null)
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.subtitle_error));
return;
}
SubtitleStreamInfo streamInfo = getSubtitleStreamInfo(index);
if (streamInfo == null) {
if (mFragment != null)
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_unable_load_subs));
return;
}
// if switching from burnt-in subtitles to another type, playback still needs to be restarted
if (burningSubs || streamInfo.getDeliveryMethod() == SubtitleDeliveryMethod.Encode) {
stop();
if (mFragment != null && streamInfo.getDeliveryMethod() == SubtitleDeliveryMethod.Encode)
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_burn_sub_warning));
play(mCurrentPosition, index);
return;
}
switch(streamInfo.getDeliveryMethod()) {
case Embed:
if (!mVideoManager.isNativeMode()) {
if (!mVideoManager.setSubtitleTrack(index, getCurrentlyPlayingItem().getMediaStreams())) {
// error selecting internal subs
if (mFragment != null)
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_unable_load_subs));
} else {
mCurrentOptions.setSubtitleStreamIndex(index);
mDefaultSubIndex = index;
}
break;
}
// not using vlc - fall through to external handling
case External:
if (mFragment != null)
mFragment.showSubLoadingMsg(true);
stream.setDeliveryMethod(SubtitleDeliveryMethod.External);
stream.setDeliveryUrl(String.format("%1$s/Videos/%2$s/%3$s/Subtitles/%4$s/0/Stream.JSON", apiClient.getValue().getApiUrl(), mCurrentStreamInfo.getItemId(), mCurrentStreamInfo.getMediaSourceId(), String.valueOf(stream.getIndex())));
apiClient.getValue().getSubtitles(stream.getDeliveryUrl(), new Response<SubtitleTrackInfo>() {
@Override
public void onResponse(final SubtitleTrackInfo info) {
if (info != null) {
Timber.d("Adding json subtitle track to player");
if (mFragment != null)
mFragment.addManualSubtitles(info);
mCurrentOptions.setSubtitleStreamIndex(index);
mDefaultSubIndex = index;
} else {
Timber.e("Empty subtitle result");
if (mFragment != null) {
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_unable_load_subs));
mFragment.showSubLoadingMsg(false);
}
}
}
@Override
public void onError(Exception ex) {
Timber.e(ex, "Error downloading subtitles");
if (mFragment != null) {
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_unable_load_subs));
mFragment.showSubLoadingMsg(false);
}
}
});
break;
case Hls:
break;
}
}
use of org.jellyfin.apiclient.model.entities.MediaStream in project jellyfin-androidtv by jellyfin.
the class StreamInfo method GetSubtitleProfiles.
public final ArrayList<SubtitleStreamInfo> GetSubtitleProfiles(boolean includeSelectedTrackOnly, boolean enableAllProfiles, String baseUrl, String accessToken) {
ArrayList<SubtitleStreamInfo> list = new ArrayList<SubtitleStreamInfo>();
// HLS will preserve timestamps so we can just grab the full subtitle stream
long startPositionTicks = getPlayMethod() == PlayMethod.Transcode ? getStartPositionTicks() : 0;
if (!includeSelectedTrackOnly) {
for (MediaStream stream : getMediaSource().getMediaStreams()) {
if (stream.getType() == MediaStreamType.Subtitle) {
AddSubtitleProfiles(list, stream, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
}
}
}
return list;
}
Aggregations