13

Question summary:

1) How to first display the video as paused, and not play it immediately?

2) How to pause/un-pause the video on touch, and also hide/show the ActionBar and MediaController.

I'd appreciate any advice. Thanks! (Relevant Code is attached)

Update 1

Found somewhat of a solution to question 2 (needed to return false), but I still don't know how to answer question 1.

When the user presses a button in my app, it takes them to watch their video. When they first open that screen, I'd like the video to be paused and not play immediately. I'd also like to be able to pause playback of the video by tapping the screen. When the video is paused, I'd like to show the ActionBar and the MediaController. When the video is resumed, I'd like to hide the ActionBar and MediaController (possibly after a slight delay?)

I've tried a few things, but I end up with problems, like the video will pause but not resume, or the ActionBar and MediaController will not show or hide properly.

Update 2

I have found a partial solution to question 1 and have updated the code to display the video as paused the first time it is opened. However, when it is opened for the first time, it only shows a black screen until I touch the videoview to play it. After watching the video once, it will reset to the beginning and pause, waiting to be played again, and will show the correct image from the beginning of the video. But I don't know how to get around the black screen at the beginning.

Relevant code:

public class ViewImageVideoFragment extends Fragment
{

    private int position = 0;
    private MediaController mMediaController;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        mMediaController = new MediaController(getActivity());
        ...
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
    {

        if (savedInstanceState != null)
        {
            position = savedInstanceState.getInt("position");
        }

        View v = inflater.inflate(R.layout.fragment_video_view, parent, false);

        mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
        mVideoView.setVideoPath(videoPath);
        mVideoView.setMediaController(mMediaController);

        mVideoView.setOnTouchListener(new View.OnTouchListener()
        {
            @Override
            public boolean onTouch(View v, MotionEvent motionEvent)
            {
                if (mVideoView.isPlaying())
                {
                    mVideoView.pause();
                    if (!getActivity().getActionBar().isShowing())
                    {
                        getActivity().getActionBar().show();
                        mMediaController.show(0);
                    }
                    position = mVideoView.getCurrentPosition();
                    return false;
                }
                else
                {
                    if (getActivity().getActionBar().isShowing())
                    {
                        getActivity().getActionBar().hide();
                        mMediaController.hide();
                    }
                    mVideoView.seekTo(position);
                    mVideoView.start();
                    return false;
                }
            }
        });

        mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
        {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer)
            {
                mVideoView.seekTo(0);
            }
        });

        if (position != 0)
        {
            mVideoView.seekTo(position);
            mVideoView.start();
        }
        else
        {
             mVideoView.seekTo(0);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState)
    {
        super.onSaveInstanceState(savedInstanceState);

        if (mVideoView != null)
        {
            savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
        }

        mVideoView.pause();
    }
}
AZ_
  • 21,688
  • 25
  • 143
  • 191
pez
  • 3,859
  • 12
  • 40
  • 72
  • 1
    Ok, so let me see if I got this right. You want to be able to start your video paused with Action and Media visible and ready to go. However, on touch (of anywhere other than action and media), you want the aforementioned to disappear and the video to start, correct? – DreadHeadedDeveloper Nov 02 '14 at 14:32
  • @DreadHeadedDeveloper Yes, that's the idea. Very similar to how the native gallery app plays videos. It starts the video paused with an option to play it, or do something in the action bar. Once you play it and stop touching it, the action bar and controller fade away and re-appear on touch or when the video is over. – pez Nov 02 '14 at 16:03
  • cool, give me a few minutes – DreadHeadedDeveloper Nov 02 '14 at 17:10
  • 1
    @pez Have you tried calling `seekTo()` from a `MediaPlayer.OnPreparedListener`? – matiash Nov 10 '14 at 23:49
  • 1
    @pez did any of these answer your question? Let me know so I can award the bounty! – DreadHeadedDeveloper Nov 14 '14 at 05:42
  • @DreadHeadedDeveloper @fifteenfiftyfive's answer worked well. @Jeff Mixon also suggested using `seekTo`, so both answers are good. Since you set the bounty, I guess you can use your judgement and decide. Thanks so much! – pez Nov 14 '14 at 05:46

3 Answers3

16

To first show the video as paused, simply change seekTo(0) to seekTo(1) in your code. This will move the video to the time at 1 millisecond and you can take it from there.

//edited here
private int position = 1;
private MediaController mMediaController;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    mMediaController = new MediaController(getActivity());
    ...
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{

    if (savedInstanceState != null)
    {
        position = savedInstanceState.getInt("position");
    }

    View v = inflater.inflate(R.layout.fragment_video_view, parent, false);

    mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
    mVideoView.setVideoPath(videoPath);
    mVideoView.setMediaController(mMediaController);

    mVideoView.setOnTouchListener(new View.OnTouchListener()
    {
        @Override
        public boolean onTouch(View v, MotionEvent motionEvent)
        {
            if (mVideoView.isPlaying())
            {
                mVideoView.pause();
                if (!getActivity().getActionBar().isShowing())
                {
                    getActivity().getActionBar().show();
                    mMediaController.show(0);
                }
                position = mVideoView.getCurrentPosition();
                return false;
            }
            else
            {
                if (getActivity().getActionBar().isShowing())
                {
                    getActivity().getActionBar().hide();
                    mMediaController.hide();
                }
                mVideoView.seekTo(position);
                mVideoView.start();
                return false;
            }
        }
    });

    mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
    {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer)
        {
            //here
            mVideoView.seekTo(1);
        }
    });
    //here
    if (position != 1)
    {
        mVideoView.seekTo(position);
        mVideoView.start();
    }
    else
    {
         //here
         mVideoView.seekTo(1);
    }
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
    super.onSaveInstanceState(savedInstanceState);

    if (mVideoView != null)
    {
        savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
    }

    mVideoView.pause();
}

}

4

If I understand correctly, you want to display a frame from the video as a placeholder until you are ready to start the video. There's two ways I know to accomplish this:

seekTo

You can use MediaPlayer.seekTo to move the video some frames ahead, for example using the value 150 to display the frame at the 150th millisecond in the video file. The video does not need to be started in order to seek.

MediaMetadataRetriever

MediaMetadataRetriever met = new MediaMetadataRetriever();

try { 
    met.setDataSource(data[0], new HashMap<String, String>()); //use this constructor, other one has a bug...
    Bitmap b = met.getFrameAtTime();

    if (b == null)
        b = met.getFrameAtTime(150, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);

    met.release();
    return b;

} catch (Exception e) {
    Log.d(TAG, "MediaMetadata failed", e);
}

This will give you a Bitmap which you can then throw in an ImageView and set in place of the video. However, this API has always been buggy for me depending on the types of video codecs you are dealing with.

Jeffrey Mixon
  • 12,846
  • 4
  • 32
  • 55
1

My sources --

show()
show(int timeout)
hide()
isShowing()
onTouchEvent()

All notes are in the code

public class ViewImageVideoFragment extends Fragment
{

   private int position = 0;
   private MediaController mMediaController;

   @Override
   public void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);
      mMediaController = new MediaController(getActivity());
   }

   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
   {

      if (savedInstanceState != null)
      {
         position = savedInstanceState.getInt("position");
      }

      v = inflater.inflate(R.layout.fragment_video_view, parent, false);

      mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
      mVideoView.setVideoPath(videoPath);
      mVideoView.setMediaController(mMediaController);

      mVideoView.setOnTouchListener(
            new View.OnTouchListener()
            {
               @Override
               public boolean onTouch(View v, MotionEvent motionEvent)
               {
                  if (mVideoView.isPlaying())
                  {
                     mVideoView.pause();


                  /*

                  Ok, so now you want to use that show(), preferrably without the int timeout

                  I didn't add it in myself but you should be able to handle it yourself

                  */

                     return true;
                  }
                  else /* I changed it to else, change it to if else if you have something specific you want to deal with */
                  {                                  

                  /* 

                  I would use that hide method I linked here, then start the 
                  video, I assume you know how to play the video yourself 

                  */

                  }

                  return false;
               }
            });

      mVideoView.seekTo(position);

      mVideoView.start();
   }

   @Override
   public void onSaveInstanceState(Bundle savedInstanceState)
   {
      super.onSaveInstanceState(savedInstanceState);

      if (mVideoView != null)
      {
         savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
      }

      mVideoView.pause();
   }
}

I provided the other methods because, depending on how you may continue, they may or may not prevent future questions.

  • Thanks for the reply. I actually have tried methods like that already, but encounter problems. I edited my main post to show one of the approaches I took. – pez Nov 02 '14 at 18:30
  • Can you point out some of the problems you ran into and/or what went wrong? – DreadHeadedDeveloper Nov 03 '14 at 03:35
  • @DreadHeadDeveloper Sorry for the long wait. The code in my main post works well for now. I'm just trying to find a way to first display the video as paused rather than immediately playing it. – pez Nov 04 '14 at 03:23
  • Ok, but what actually happens? I assume you debugged it, did it not listen to the method that told it to pause the video? – DreadHeadedDeveloper Nov 04 '14 at 04:36
  • The actionbar works as expected- show on pause, hide on play. The mediacontroller doesn't seem to listen despite my calls to hide/show. It should hide/show with the actionbar, but it still behaves as if I had not implemented any calls to hide/show it. – pez Nov 04 '14 at 04:42
  • Perhaps a bounty then? I want to set one up but I don't see the option to – DreadHeadedDeveloper Nov 04 '14 at 05:45
  • If you're interested in the answer and decide to set a bounty, i would appreciate it. I believe this question will be eligible for a bounty two days after the original posting date. – pez Nov 04 '14 at 05:49
  • 1
    A bounty it is then, sorry I couldn't help more – DreadHeadedDeveloper Nov 04 '14 at 05:50
  • I appreciate the effort! Everything helps – pez Nov 04 '14 at 05:50