OnTimedTextMethod медиаплеера не вызывается

Я пишу медиаплеер для Android TV. Я загрузил .srt файл субтитров из папки сырых ресурсов и добавил его с помощью addTimedTextSource как показано ниже, но onTimedText метод не вызывается.

Я использую библиотеку Leanback v23.0.1 на Android 7.1.1.

Ниже мой код:

public abstract class MediaPlayerGlue extends PlaybackControlGlue 
  implements OnItemViewSelectedListener,MediaPlayer.OnTimedTextListener {

  public static final int FAST_FORWARD_REWIND_STEP = 10 * 1000; // in ms
  public static final int FAST_FORWARD_REWIND_REPEAT_DELAY = 200; // in ms
  private static final String TAG = "MediaPlayerGlue";
  protected final PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
  protected final PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
  private final Context mContext;
  private final MediaPlayer mPlayer = new MediaPlayer();
  private final PlaybackControlsRow.RepeatAction mRepeatAction;
  private final PlaybackControlsRow.ShuffleAction mShuffleAction;
  private PlaybackControlsRow mControlsRow;
  private Runnable mRunnable;
  private Handler mHandler = new Handler();
  private boolean mPaused = false;
  private boolean mInitialized = false; // true when the MediaPlayer is prepared/initialized
  private OnMediaFileFinishedPlayingListener mMediaFileFinishedPlayingListener;
  private OnEveryHalfMinute onEveryHalfMinute;
  private OnShowSubtitle onShowSubtitle;

  private Action mSelectedAction; // the action which is currently selected by  the user
  private long mLastKeyDownEvent = 0L; // timestamp when the last DPAD_CENTER KEY_DOWN occurred
  private MetaData mMetaData;
  private Uri mMediaSourceUri = null;
  private String mMediaSourcePath = null;
  private String mMediaSubTitlePath = null;
  private String sub_sub = "1\n" +
        "00:00:00,220 --> 00:00:01,215\n" +
        "<b>COMPAÑÍA DE\n" +
        "PUBLICIDAD EBBING</b>";

public MediaPlayerGlue(Context context, PlaybackOverlayFragment fragment) {
    super(context, fragment, new int[]{1});
    mContext = context;

    // Instantiate secondary actions
    mShuffleAction = new PlaybackControlsRow.ShuffleAction(mContext);
    mRepeatAction = new PlaybackControlsRow.RepeatAction(mContext);
    mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(mContext);
    mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(mContext);
    mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
    mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);

    // Setup controls and notify UI about change.
    setFadingEnabled(false);
    onStateChanged();

    // Register selected listener such that we know what action the user currently has focused.
    fragment.setOnItemViewSelectedListener(this);
}

/**
 * Will reset the {@link MediaPlayer} and the glue such that a new file can 
be played. You are
 * not required to call this method before playing the first file. However 
 you have to call it
 * before playing a second one.
 */
public void reset() {
    mPaused = mInitialized = false;
    mPlayer.reset();
}

public void 
setOnMediaFileFinishedPlayingListener(OnMediaFileFinishedPlayingListener 
 listener) {
    mMediaFileFinishedPlayingListener = listener;
}

public void setOnHalfMinute(OnEveryHalfMinute onEveryHalfMinute) {
    this.onEveryHalfMinute = onEveryHalfMinute;
}
public void setOnShowSubtitle(OnShowSubtitle onShowSubtitle) {
    this.onShowSubtitle = onShowSubtitle;
}


/**
 * Override this method in case you need to add different secondary actions.
 *
 * @param secondaryActionsAdapter The adapter you need to add the {@link Action}s to.
 */
protected void addSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) {
    secondaryActionsAdapter.add(mShuffleAction);
    secondaryActionsAdapter.add(mRepeatAction);
    secondaryActionsAdapter.add(mThumbsDownAction);
    secondaryActionsAdapter.add(mThumbsUpAction);
}

/**
 * @see MediaPlayer#setDisplay(SurfaceHolder)
 */
public void setDisplay(SurfaceHolder surfaceHolder) {
    mPlayer.setDisplay(surfaceHolder);
}

/**
 * Use this method to setup the {@link PlaybackControlsRowPresenter}. It'll be called
 * <u>after</u> the {@link PlaybackControlsRowPresenter} has been created and the primary and
 * secondary actions have been added.
 *
 * @param presenter The PlaybackControlsRowPresenter used to display the controls.
 */
public void setupControlsRowPresenter(PlaybackControlsRowPresenter presenter) {
    // TODO: hahnr@ move into resources
    presenter.setProgressColor(Color.BLUE);
    presenter.setBackgroundColor(Color.BLACK);
}

@Override
public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
    PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
    mControlsRow = getControlsRow();

    // Add secondary actions and change the control row color.
    ArrayObjectAdapter secondaryActions = new ArrayObjectAdapter(
            new ControlButtonPresenterSelector());
    mControlsRow.setSecondaryActionsAdapter(secondaryActions);
    addSecondaryActions(secondaryActions);
    setupControlsRowPresenter(presenter);
    return presenter;
}

int recentRequestTime = 0;

@Override
public void enableProgressUpdating(final boolean enabled) {
    if (!enabled) {
        if (mRunnable != null) mHandler.removeCallbacks(mRunnable);
        return;
    }
    mRunnable = new Runnable() {
        @Override
        public void run() {

            updateProgress();
            Log.d(TAG, "enableProgressUpdating(boolean)");
            if (onEveryHalfMinute != null) {
                int currentTime = getCurrentPosition();
                int currentTimeInSec = currentTime / 1000;
                if (currentTimeInSec != 0) {
                    if (currentTimeInSec % 15 == 0) {
                        //  if (recentRequestTime != currentTime) {
                        onEveryHalfMinute.onHalfMinute(currentTimeInSec);
                        recentRequestTime = currentTimeInSec / 15;
                        // }
                    }
                }
            }
            mHandler.postDelayed(this, 1000);
        }
    };
    mHandler.postDelayed(mRunnable, 1000);
}

@Override
public void onActionClicked(Action action) {
    // If either 'Shuffle' or 'Repeat' has been clicked we need to make sure the acitons index
    // is incremented and the UI updated such that we can display the new state.
    super.onActionClicked(action);
    if (action instanceof PlaybackControlsRow.ShuffleAction) {
        mShuffleAction.nextIndex();
    } else if (action instanceof PlaybackControlsRow.RepeatAction) {
        mRepeatAction.nextIndex();
    } else if (action instanceof PlaybackControlsRow.ThumbsUpAction) {
        if (mThumbsUpAction.getIndex() == PlaybackControlsRow.ThumbsAction.SOLID) {
            mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
        } else {
            mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.SOLID);
            mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
        }
    } else if (action instanceof PlaybackControlsRow.ThumbsDownAction) {
        if (mThumbsDownAction.getIndex() == PlaybackControlsRow.ThumbsAction.SOLID) {
            mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
        } else {
            mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.SOLID);
            mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
        }
    }
    onMetadataChanged();
}

@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
    // This method is overridden in order to make implement fast forwarding and rewinding when
    // the user keeps the corresponding action pressed.
    // We only consume DPAD_CENTER Action_DOWN events on the Fast-Forward and Rewind action and
    // only if it has not been pressed in the last X milliseconds.
    boolean consume = mSelectedAction instanceof PlaybackControlsRow.RewindAction;
    consume = consume || mSelectedAction instanceof PlaybackControlsRow.FastForwardAction;
    consume = consume && mInitialized;
    consume = consume && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER;
    consume = consume && event.getAction() == KeyEvent.ACTION_DOWN;
    consume = consume && System
            .currentTimeMillis() - mLastKeyDownEvent > FAST_FORWARD_REWIND_REPEAT_DELAY;
    if (consume) {
        mLastKeyDownEvent = System.currentTimeMillis();
        int newPosition = getCurrentPosition() + FAST_FORWARD_REWIND_STEP;
        if (mSelectedAction instanceof PlaybackControlsRow.RewindAction) {
            newPosition = getCurrentPosition() - FAST_FORWARD_REWIND_STEP;
        }
        // Make sure the new calculated duration is in the range 0 >= X >= MediaDuration
        if (newPosition < 0) newPosition = 0;
        if (newPosition > getMediaDuration()) newPosition = getMediaDuration();
        seekTo(newPosition);
        return true;
    }
    return super.onKey(v, keyCode, event);
}

@Override
public boolean hasValidMedia() {
    return mMetaData != null;
}

@Override
public boolean isMediaPlaying() {
    return mPlayer.isPlaying();
}

@Override
public CharSequence getMediaTitle() {
    return hasValidMedia() ? mMetaData.getTitle() : "N/a";
}

@Override
public CharSequence getMediaSubtitle() {
    return hasValidMedia() ? mMetaData.getArtist() : "N/a";
}

@Override
public int getMediaDuration() {
    return mInitialized ? mPlayer.getDuration() : 0;
}

@Override
public Drawable getMediaArt() {
    return hasValidMedia() ? mMetaData.getCover() : null;
}

@Override
public long getSupportedActions() {
    return PlaybackControlGlue.ACTION_PLAY_PAUSE |
            PlaybackControlGlue.ACTION_FAST_FORWARD |
            PlaybackControlGlue.ACTION_REWIND;
}

@Override
public int getCurrentSpeedId() {
    // 0 = Pause, 1 = Normal Playback Speed
    return mPlayer.isPlaying() ? 1 : 0;
}

@Override
public int getCurrentPosition() {
    return mInitialized ? mPlayer.getCurrentPosition() : 0;
}

@Override
protected void startPlayback(int speed) throws IllegalStateException {
    if (mPaused) {
        mPlayer.start();
    } else if (!isMediaPlaying()) {
        reset();
        try {
            if (mMediaSourceUri != null) {
                mPlayer.setDataSource(getContext(), mMediaSourceUri);
            } else {
                mPlayer.setDataSource(mMediaSourcePath);

            }


        } catch (Exception e) {
            UtilMethods.LogMethod("downloadSubtitle123_ooooo", String.valueOf(e));
            //throw new RuntimeException(e);
        }
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                recentRequestTime = 0;
                mInitialized = true;
                mPaused = false;
                if (mMediaSubTitlePath != null) {
                    //  String mimeType = UtilMethods.getMimeType(mMediaSubTitlePath);
                     UtilMethods.LogMethod("downloadSubtitle123_mMediaSubTitlePath444",getSubtitleFile(R.raw.sub));
                    try {
                        mPlayer.addTimedTextSource(getSubtitleFile(R.raw.sub),
                                MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP);
                        int textTrackIndex = findTrackIndexFor(
                                MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT, mPlayer.getTrackInfo());
                        if (textTrackIndex >= 0) {
                            UtilMethods.LogMethod("downloadSubtitle123_trackInfo", "iffff");
                            mPlayer.selectTrack(textTrackIndex);
                        } else {
                            UtilMethods.LogMethod("downloadSubtitle123_trackInfo", "elseee");
                        }

                    } catch (IOException e) {
                        UtilMethods.LogMethod("downloadSubtitle123_aaaaa_qweerrwqq", String.valueOf(e));
                        e.printStackTrace();
                    }
                }
                //mPlayer.setOnTimedTextListener(MediaPlayerGlue.this);
                mPlayer.start();
                onMetadataChanged();
                onStateChanged();
                updateProgress();
            }
        });
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if (mInitialized && mMediaFileFinishedPlayingListener != null)
                    mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
            }
        });
        mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
            @Override
            public void onBufferingUpdate(MediaPlayer mp, int percent) {
                mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
            }
        });

        mPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
            @Override
            public void onTimedText(MediaPlayer mp, TimedText text) {
                UtilMethods.LogMethod("downloadSubtitle123_onTimedText_2222222", "22222222");
                if(onShowSubtitle!=null){
                    onShowSubtitle.showSubtitle(mp,text);
                }
            }
        });


        mPlayer.prepareAsync();

        onStateChanged();


    }
}

@Override
protected void pausePlayback() {
    if (mPlayer.isPlaying()) {
        mPlayer.pause();
        mPaused = true;
    }
}

@Override
protected void skipToNext() {
    // Not supported.
}

@Override
protected void skipToPrevious() {
    // Not supported.
}

/**
 * Called whenever the user presses fast-forward/rewind or when the user keeps the corresponding
 * action pressed.
 *
 * @param newPosition The new position of the media track in milliseconds.
 */
protected void seekTo(int newPosition) {
    mPlayer.seekTo(newPosition);
}

/**
 * @see MediaPlayer#setDataSource(Context, Uri)
 */
public void setMediaSource(Uri uri) {
    mMediaSourceUri = uri;
}

/**
 * @see MediaPlayer#setDataSource(String)
 */
public void setMediaSource(String path) {
    mMediaSourcePath = path;
}

public void setmMediaSubTitlePath(String path) {
    mMediaSubTitlePath = path;
}

/**
 * Call to <code>startPlayback(1)</code>.
 *
 * @throws IllegalStateException See {@link MediaPlayer} for further information about it's
 *                               different states when setting a data source and preparing it to be played.
 */
public void startPlayback() throws IllegalStateException {
    startPlayback(1);
}

/**
 * @return Returns <code>true</code> iff 'Shuffle' is <code>ON</code>.
 */
public boolean useShuffle() {
    return mShuffleAction.getIndex() == PlaybackControlsRow.ShuffleAction.ON;
}

/**
 * @return Returns <code>true</code> iff 'Repeat-One' is <code>ON</code>.
 */
public boolean repeatOne() {
    return mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.ONE;
}

/**
 * @return Returns <code>true</code> iff 'Repeat-All' is <code>ON</code>.
 */
public boolean repeatAll() {
    return mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.ALL;
}

public void setMetaData(MetaData metaData) {
    mMetaData = metaData;
    onMetadataChanged();
}

/**
 * This is a listener implementation for the {@link OnItemViewSelectedListener} of the {@link
 * PlaybackOverlayFragment}. This implementation is required in order to detect KEY_DOWN events
 * on the {@link PlaybackControlsRow.FastForwardAction} and
 * {@link PlaybackControlsRow.RewindAction}. Thus you should
 * <u>NOT</u> set another {@link OnItemViewSelectedListener} on your {@link
 * PlaybackOverlayFragment}. Instead, override this method and call its super (this)
 * implementation.
 *
 * @see OnItemViewSelectedListener#( Presenter.ViewHolder, Object,
 * RowPresenter.ViewHolder, Row )
 */
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
                           RowPresenter.ViewHolder rowViewHolder, Row row) {
    if (item instanceof Action) {
        mSelectedAction = (Action) item;
    } else {
        mSelectedAction = null;
    }
}

/**
 * A listener which will be called whenever a track is finished playing.
 */
public interface OnMediaFileFinishedPlayingListener {

    /**
     * Called when a track is finished playing.
     *
     * @param metaData The track's {@link MetaData} which just finished playing.
     */
    void onMediaFileFinishedPlaying(MetaData metaData);

}

public interface OnEveryHalfMinute {
    void onHalfMinute(int currentTime);
}

public interface OnShowSubtitle {
    void showSubtitle(MediaPlayer mp, TimedText text);
}

/**
 * Holds the meta data such as track title, artist and cover art. It'll be used by the {@link
 * MediaPlayerGlue}.
 */
public static class MetaData {

    private String mTitle;
    private String mArtist;
    private Drawable mCover;


    public String getTitle() {
        return mTitle;
    }

    public void setTitle(String title) {
        this.mTitle = title;
    }

    public String getArtist() {
        return mArtist;
    }

    public void setArtist(String artist) {
        this.mArtist = artist;
    }

    public Drawable getCover() {
        return mCover;
    }

    public void setCover(Drawable cover) {
        this.mCover = cover;
    }
}

private int findTrackIndexFor(int mediaTrackType, MediaPlayer.TrackInfo[] trackInfo) {
    int index = -1;
    UtilMethods.LogMethod("downloadSubtitle123_length", String.valueOf(trackInfo.length));
    for (int i = 0; i < trackInfo.length; i++) {
        UtilMethods.LogMethod("downloadSubtitle123_type", String.valueOf(trackInfo[i].getTrackType()));
        if (trackInfo[i].getTrackType() == mediaTrackType) {
            return i;
        }
    }
    return index;
}

private String getSubtitleFile(int resId) {
    String fileName = mContext.getResources().getResourceEntryName(resId);
    File subtitleFile = mContext.getFileStreamPath(fileName);
    Log.d(TAG, "Subtitle does not exists, copy it from res/raw");

    // Copy the file from the res/raw folder to your app folder on the
    // device
    InputStream inputStream = null;
    OutputStream outputStream = null;
    try {
        inputStream = mContext.getResources().openRawResource(resId);
        outputStream = new FileOutputStream(subtitleFile, false);
        copyFile(inputStream, outputStream);
        return subtitleFile.getAbsolutePath();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        closeStreams(inputStream, outputStream);
    }
    return "";
}

private void copyFile(InputStream inputStream, OutputStream outputStream)
        throws IOException {
    final int BUFFER_SIZE = 1024;
    byte[] buffer = new byte[BUFFER_SIZE];
    int length = -1;
    while ((length = inputStream.read(buffer)) != -1) {
        outputStream.write(buffer, 0, length);
    }
}

// A handy method I use to close all the streams
private void closeStreams(Closeable... closeables) {
    if (closeables != null) {
        for (Closeable stream : closeables) {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  }
}

0 ответов

Другие вопросы по тегам