Search in sources :

Example 1 with MediaStream

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;
            }
        }
    }
}
Also used : MediaStream(org.jellyfin.apiclient.model.entities.MediaStream)

Example 2 with MediaStream

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;
}
Also used : TracksInfo(com.google.android.exoplayer2.TracksInfo) PlaybackException(com.google.android.exoplayer2.PlaybackException) TrackSelectionOverrides(com.google.android.exoplayer2.trackselection.TrackSelectionOverrides) PixelFormat(android.graphics.PixelFormat) Format(com.google.android.exoplayer2.Format) MediaStream(org.jellyfin.apiclient.model.entities.MediaStream) TrackSelectionParameters(com.google.android.exoplayer2.trackselection.TrackSelectionParameters) TrackGroup(com.google.android.exoplayer2.source.TrackGroup)

Example 3 with MediaStream

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));
            }
        }
    }
}
Also used : UserPreferences(org.jellyfin.androidtv.preference.UserPreferences) MediaStream(org.jellyfin.apiclient.model.entities.MediaStream) HeaderItem(androidx.leanback.widget.HeaderItem) ArrayObjectAdapter(androidx.leanback.widget.ArrayObjectAdapter) ListRow(androidx.leanback.widget.ListRow) MediaSourceInfo(org.jellyfin.apiclient.model.dto.MediaSourceInfo) InfoCardPresenter(org.jellyfin.androidtv.ui.presentation.InfoCardPresenter)

Example 4 with MediaStream

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;
    }
}
Also used : MediaStream(org.jellyfin.apiclient.model.entities.MediaStream) SubtitleTrackInfo(org.jellyfin.apiclient.model.mediainfo.SubtitleTrackInfo) SubtitleStreamInfo(org.jellyfin.androidtv.data.compat.SubtitleStreamInfo) PlaybackException(org.jellyfin.androidtv.data.compat.PlaybackException)

Example 5 with MediaStream

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;
}
Also used : MediaStream(org.jellyfin.apiclient.model.entities.MediaStream) ArrayList(java.util.ArrayList)

Aggregations

MediaStream (org.jellyfin.apiclient.model.entities.MediaStream)8 ArrayList (java.util.ArrayList)2 PixelFormat (android.graphics.PixelFormat)1 MenuItem (android.view.MenuItem)1 PopupMenu (android.widget.PopupMenu)1 ArrayObjectAdapter (androidx.leanback.widget.ArrayObjectAdapter)1 HeaderItem (androidx.leanback.widget.HeaderItem)1 ListRow (androidx.leanback.widget.ListRow)1 Format (com.google.android.exoplayer2.Format)1 PlaybackException (com.google.android.exoplayer2.PlaybackException)1 TracksInfo (com.google.android.exoplayer2.TracksInfo)1 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)1 TrackSelectionOverrides (com.google.android.exoplayer2.trackselection.TrackSelectionOverrides)1 TrackSelectionParameters (com.google.android.exoplayer2.trackselection.TrackSelectionParameters)1 PlaybackException (org.jellyfin.androidtv.data.compat.PlaybackException)1 SubtitleStreamInfo (org.jellyfin.androidtv.data.compat.SubtitleStreamInfo)1 UserPreferences (org.jellyfin.androidtv.preference.UserPreferences)1 PlaybackManager (org.jellyfin.androidtv.ui.playback.PlaybackManager)1 InfoCardPresenter (org.jellyfin.androidtv.ui.presentation.InfoCardPresenter)1 MediaSourceInfo (org.jellyfin.apiclient.model.dto.MediaSourceInfo)1