Search code examples
androidvitamio

In Vitamio When I drag the seekBar, the progress bar is inaccurate? How to fix it?


I am using Vitamio Library in my app. But the problem is, while playing when i try to move seek bar forward or backward the progress bar is in accurate.

I debug the code and found that, in setProgress() method in MediaController class:

long position = mPlayer.getCurrentPosition();

this position is always same. I am not getting that why getCurrentPosition() is always returning same value.

I also search it on Vitamio website and i found:

https://www.vitamio.org/en/docs/FAQ/2013/0509/6.html

When I drag the seekBar, Why the progress bar is inaccurate?

It's all right, this isn't Vitamio's bug, because you must drag the seekBar to the key frame, But the key frame is not always on every timestamp, except you use the intra-only encoding.

What does this mean? and how can i fix it. Please help me.


Solution

  • In Vitamio When I drag the seekBar, the progress bar is inaccurate? How to fix it?

    I just wanted to tell you all that I had made a custom solution to fix this issue. You can take help from this solution If you still facing this issue. I have made changes in MediaController.java class in library. You just need to replace this class from your previous class and then run your code.

    package io.vov.vitamio.widget;
    
    import android.annotation.SuppressLint;
    import android.annotation.TargetApi;
    import android.content.Context;
    import android.graphics.Rect;
    import android.media.AudioManager;
    import android.os.Build;
    import android.os.Handler;
    import android.os.Message;
    import android.util.AttributeSet;
    import android.view.Gravity;
    import android.view.KeyEvent;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.FrameLayout;
    import android.widget.ImageButton;
    import android.widget.PopupWindow;
    import android.widget.SeekBar;
    import android.widget.SeekBar.OnSeekBarChangeListener;
    import android.widget.TextView;
    
    import java.lang.reflect.Method;
    
    import io.vov.vitamio.utils.Log;
    import io.vov.vitamio.utils.StringUtils;
    
    public class MediaController extends FrameLayout {
        private static final int sDefaultTimeout = 3000;
        private static final int FADE_OUT = 1;
        private static final int SHOW_PROGRESS = 2;
        private MediaPlayerControl mPlayer;
        private Context mContext;
        private PopupWindow mWindow;
        private int mAnimStyle;
        private View mAnchor;
        private View mRoot;
        private SeekBar mProgress;
        private TextView mEndTime, mCurrentTime;
        private TextView mFileName;
        private OutlineTextView mInfoView;
        private String mTitle;
        private long mDuration;
        private boolean mShowing;
        private boolean mDragging;
        private boolean mInstantSeeking = false;
        private boolean mFromXml = false;
        private ImageButton mPauseButton;
        private AudioManager mAM;
        private OnShownListener mShownListener;
        private OnHiddenListener mHiddenListener;
        private boolean isSeekBar = false; // Change for video time stuck
        private boolean isPlayButtonVisible = false; // Change for video time stuck
    
        @SuppressLint("HandlerLeak")
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                long pos;
                switch (msg.what) {
                case FADE_OUT:
                    hide();
                    break;
                case SHOW_PROGRESS:
                    if(!isSeekBar){ // Change for video time stuck
    
                        pos = setProgress();
                        if (!mDragging && mShowing) {
                            msg = obtainMessage(SHOW_PROGRESS);
                            sendMessageDelayed(msg, 1000 - (pos % 1000));
    //                      updatePausePlay(); // Change for video time stuck
                        }
                    }
                    break;
                }
            }
        };
        private View.OnClickListener mPauseListener = new View.OnClickListener() {
            public void onClick(View v) {
                doPauseResume();
                show(sDefaultTimeout);
            }
        };
        private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
            public void onStartTrackingTouch(SeekBar bar) {
                if(mPlayer.isPlaying()){ // // Change for video time stuck
                    isSeekBar = true; // // Change for video time stuck
                    mDragging = true;
                    show(3600000);
                    mHandler.removeMessages(SHOW_PROGRESS);
                    if (mInstantSeeking)
                        mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
                    if (mInfoView != null) {
                        mInfoView.setText("");
                        mInfoView.setVisibility(View.VISIBLE);
                    }
                }
            }
    
            public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
                if (!fromuser)
                    return;
                if(mPlayer.isPlaying()){ // // Change for video time stuck
                    long newposition = (mDuration * progress) / 1000;
                    String time = StringUtils.generateTime(newposition);
                    if (mInstantSeeking)
                        mPlayer.seekTo(newposition);
                    if (mInfoView != null)
                        mInfoView.setText(time);
                    if (mCurrentTime != null)
                        mCurrentTime.setText(time);
                }
            }
    
            public void onStopTrackingTouch(SeekBar bar) {
                isSeekBar = false; // // Change for video time stuck
    
                if(mPlayer.isPlaying()){ // // Change for video time stuck
                    if (!mInstantSeeking)
                        mPlayer.seekTo((mDuration * bar.getProgress()) / 1000);
                    if (mInfoView != null) {
                        mInfoView.setText("");
                        mInfoView.setVisibility(View.GONE);
                    }
                    show(sDefaultTimeout);
                    mHandler.removeMessages(SHOW_PROGRESS);
                    mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
                    mDragging = false;
                    mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
                }
            }
        };
    
        public MediaController(Context context, AttributeSet attrs) {
            super(context, attrs);
            mRoot = this;
            mFromXml = true;
            initController(context);
        }
    
        public MediaController(Context context) {
            super(context);
            if (!mFromXml && initController(context))
                initFloatingWindow();
        }
    
        private boolean initController(Context context) {
            mContext = context;
            mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
            return true;
        }
    
        @Override
        public void onFinishInflate() {
            if (mRoot != null)
                initControllerView(mRoot);
        }
    
        private void initFloatingWindow() {
            mWindow = new PopupWindow(mContext);
            mWindow.setFocusable(false);
            mWindow.setBackgroundDrawable(null);
            mWindow.setOutsideTouchable(true);
            mAnimStyle = android.R.style.Animation;
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        public void setWindowLayoutType() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                try {
                    mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
                    Method setWindowLayoutType = PopupWindow.class.getMethod("setWindowLayoutType", new Class[] { int.class });
                    setWindowLayoutType.invoke(mWindow, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
                } catch (Exception e) {
                    Log.e("setWindowLayoutType", e);
                }
            }
        }
    
        /**
         * Set the view that acts as the anchor for the control view. This can for
         * example be a VideoView, or your Activity's main view.
         *
         * @param view The view to which to anchor the controller when it is visible.
         */
        public void setAnchorView(View view) {
            mAnchor = view;
            if (!mFromXml) {
                removeAllViews();
                mRoot = makeControllerView();
                mWindow.setContentView(mRoot);
                mWindow.setWidth(LayoutParams.MATCH_PARENT);
                mWindow.setHeight(LayoutParams.WRAP_CONTENT);
            }
            initControllerView(mRoot);
        }
    
        /**
         * Create the view that holds the widgets that control playback. Derived
         * classes can override this to create their own.
         *
         * @return The controller view.
         */
        protected View makeControllerView() {
            return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(getResources().getIdentifier("mediacontroller", "layout", mContext.getPackageName()), this);
        }
    
        private void initControllerView(View v) {
            mPauseButton = (ImageButton) v.findViewById(getResources().getIdentifier("mediacontroller_play_pause", "id", mContext.getPackageName()));
            if (mPauseButton != null) {
                mPauseButton.requestFocus();
                mPauseButton.setOnClickListener(mPauseListener);
            }
    
            mProgress = (SeekBar) v.findViewById(getResources().getIdentifier("mediacontroller_seekbar", "id", mContext.getPackageName()));
            if (mProgress != null) {
                if (mProgress instanceof SeekBar) {
                    SeekBar seeker = (SeekBar) mProgress;
                    seeker.setOnSeekBarChangeListener(mSeekListener);
                }
                mProgress.setMax(1000);
            }
    
            mEndTime = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_time_total", "id", mContext.getPackageName()));
            mCurrentTime = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_time_current", "id", mContext.getPackageName()));
            mFileName = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_file_name", "id", mContext.getPackageName()));
            if (mFileName != null)
                mFileName.setText(mTitle);
        }
    
        public void setMediaPlayer(MediaPlayerControl player) {
            mPlayer = player;
            updatePausePlay();
        }
    
        /**
         * Control the action when the seekbar dragged by user
         *
         * @param seekWhenDragging True the media will seek periodically
         */
        public void setInstantSeeking(boolean seekWhenDragging) {
            mInstantSeeking = seekWhenDragging;
        }
    
        public void show() {
            show(sDefaultTimeout);
        }
    
        /**
         * Set the content of the file_name TextView
         *
         * @param name
         */
        public void setFileName(String name) {
            mTitle = name;
            if (mFileName != null)
                mFileName.setText(mTitle);
        }
    
        /**
         * Set the View to hold some information when interact with the
         * MediaController
         *
         * @param v
         */
        public void setInfoView(OutlineTextView v) {
            mInfoView = v;
        }
    
        /**
         * <p>
         * Change the animation style resource for this controller.
         * </p>
         * <p/>
         * <p>
         * If the controller is showing, calling this method will take effect only the
         * next time the controller is shown.
         * </p>
         *
         * @param animationStyle animation style to use when the controller appears
         *                       and disappears. Set to -1 for the default animation, 0 for no animation, or
         *                       a resource identifier for an explicit animation.
         */
        public void setAnimationStyle(int animationStyle) {
            mAnimStyle = animationStyle;
        }
    
        /**
         * Show the controller on screen. It will go away automatically after
         * 'timeout' milliseconds of inactivity.
         *
         * @param timeout The timeout in milliseconds. Use 0 to show the controller
         *                until hide() is called.
         */
        public void show(int timeout) {
            if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) {
                if (mPauseButton != null)
                    mPauseButton.requestFocus();
    
                if (mFromXml) {
                    setVisibility(View.VISIBLE);
                } else {
                    int[] location = new int[2];
                    mAnchor.getLocationOnScreen(location);
                    Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
    
                    mWindow.setAnimationStyle(mAnimStyle);
                    setWindowLayoutType();
                    mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom);
                }
                mShowing = true;
                if (mShownListener != null)
                    mShownListener.onShown();
            }
    //      updatePausePlay(); // Change for video time stuck
    
            mHandler.sendEmptyMessage(SHOW_PROGRESS);
    
            if (timeout != 0) {
                mHandler.removeMessages(FADE_OUT);
                mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout);
            }
        }
    
        public boolean isShowing() {
            return mShowing;
        }
    
        public void hide() {
            if (mAnchor == null)
                return;
    
            if (mShowing) {
                try {
                    mHandler.removeMessages(SHOW_PROGRESS);
                    if (mFromXml)
                        setVisibility(View.GONE);
                    else
                        mWindow.dismiss();
                } catch (IllegalArgumentException ex) {
                    Log.d("MediaController already removed");
                }
                mShowing = false;
                if (mHiddenListener != null)
                    mHiddenListener.onHidden();
            }
        }
    
        public void setOnShownListener(OnShownListener l) {
            mShownListener = l;
        }
    
        public void setOnHiddenListener(OnHiddenListener l) {
            mHiddenListener = l;
        }
    
        private long setProgress() {
            if (mPlayer == null || mDragging)
                return 0;
    
            long position = mPlayer.getCurrentPosition();
            long duration = mPlayer.getDuration();
            if (mProgress != null) {
                if (duration > 0) {
                    long pos = 1000L * position / duration;
                    mProgress.setProgress((int) pos);
                }
                int percent = mPlayer.getBufferPercentage();
                mProgress.setSecondaryProgress(percent * 10);
            }
    
            mDuration = duration;
    
            if (mEndTime != null)
                mEndTime.setText(StringUtils.generateTime(mDuration));
            if (mCurrentTime != null)
                mCurrentTime.setText(StringUtils.generateTime(position));
    
            return position;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            show(sDefaultTimeout);
            return true;
        }
    
        @Override
        public boolean onTrackballEvent(MotionEvent ev) {
            show(sDefaultTimeout);
            return false;
        }
    
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            int keyCode = event.getKeyCode();
            if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
                doPauseResume();
                show(sDefaultTimeout);
                if (mPauseButton != null)
                    mPauseButton.requestFocus();
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
                if (mPlayer.isPlaying()) {
                    mPlayer.pause();
                    updatePausePlay();
                }
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
                hide();
                return true;
            } else {
                show(sDefaultTimeout);
            }
            return super.dispatchKeyEvent(event);
        }
    
        private void updatePausePlay() {
            if (mRoot == null || mPauseButton == null)
                return;
    
            if (mPlayer.isPlaying()){
                isPlayButtonVisible = false; // // Change for video time stuck
                mPauseButton.setImageResource(getResources().getIdentifier("mediacontroller_pause", "drawable", mContext.getPackageName()));
            }else{
                isPlayButtonVisible = true; // // Change for video time stuck
                mPauseButton.setImageResource(getResources().getIdentifier("mediacontroller_play", "drawable", mContext.getPackageName()));
            }
        }
    
        private void doPauseResume() {
            if (mPlayer.isPlaying())
                mPlayer.pause();
            else
                mPlayer.start();
            updatePausePlay();
        }
    
        @Override
        public void setEnabled(boolean enabled) {
            if (mPauseButton != null)
                mPauseButton.setEnabled(enabled);
            if (mProgress != null)
                mProgress.setEnabled(enabled);
            super.setEnabled(enabled);
        }
    
        public interface OnShownListener {
            public void onShown();
        }
    
        public interface OnHiddenListener {
            public void onHidden();
        }
    
        public interface MediaPlayerControl {
            void start();
    
            void pause();
    
            long getDuration();
    
            long getCurrentPosition();
    
            void seekTo(long pos);
    
            boolean isPlaying();
    
            int getBufferPercentage();
        }
    
    }