74

I created an VideoView in my activity, below is the code.

VideoView vvVideos = (VideoView) rootView.findViewById(R.id.videoView);
MediaController mediacontroller = new MediaController(ctx);
mediacontroller.setAnchorView(vvVideos);
    Uri video = Uri.parse("android.resource://" + packageName +"/"+R.raw.sample);
    vvVideos.setMediaController(mediacontroller);

    LayoutParams params=vvVideos.getLayoutParams();
    params.height=150;
    vvVideos.setLayoutParams(params);

    vvVideos.setVideoURI(video);
    vvVideos.requestFocus();
    vvVideos.setOnPreparedListener(new OnPreparedListener() {
        public void onPrepared(MediaPlayer mp) {
            vvVideos.start();
        }
    });

Now the video gets started to play when the activity gets created. I want to make my activity as follows

  1. Video should not play when the activity gets open.
  2. It shoud display the starting video image(currently its displaying black color)
  3. It should play only when the user click on the video.
    please help me.
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Vignesh
  • 2,295
  • 7
  • 33
  • 41

12 Answers12

141

Use seekTo( 1 ) to show the first frame.

Ensure the movie is paused and then use seekTo() to show the first frame of the video:

VideoView mVideoView = (VideoView) findViewById( R.id.video_preview );

mVideoView.setVideoURI( yourVideoPath );

mVideoView.seekTo( 1 );                 // 1 millisecond (0.001 s) into the clip.

NOTE: We use .seekTo( 1 ) because setting .seekTo( 0 ) did not work on Android 9.

To have it play when clicked on has been answered by @Lingviston in another answer.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
  • 5
    thnaks man, you saved my day! btw, calling `mVideoView.seekTo(0);` has the same result of loading the first frame – Guillaume Apr 23 '14 at 14:22
  • @snayde Thanks for the heads up, haven't tried it on 5 yet. – Joshua Pinter Mar 16 '15 at 17:15
  • fails to work on my Nexus 5 as well... still looking for a solution without using MediaPlayer and textureview – Lion789 May 08 '15 at 20:09
  • 1
    Works on Panasonic CM1 with Android 5. Seems to depend on the standard video player installed on the device. – OneWorld Mar 22 '16 at 14:35
  • 3
    It works on Android 5 too, if you go to the developer-settings and set the media-player to "AwesomePlayer" (the old one). That's not a production fix (obviously), but it clears up what the problem is. – Lukas Knuth Sep 27 '16 at 07:17
  • 1
    Android 9 here. `.seekTo(0);` didn't work for me, but `.seekTo(100);` did the trick. Thanks! – rjr-apps Oct 29 '18 at 21:57
  • @nope4561759 Thanks for confirming! Can you try using `.seekTo(10)` and `.seekTo(1)` to see if those work as well? Thanks! – Joshua Pinter Oct 30 '18 at 00:21
  • 1
    I can confirm that both `.seekTo(1)` and `seekTo(10)` worked just fine. – rjr-apps Oct 31 '18 at 14:15
  • 1
    @nope4561759 Nicely done! Really appreciate you confirming that. I'm going to update my answer to reflect `.seekTo(1)` because I think that's what most people would want to do. – Joshua Pinter Oct 31 '18 at 14:29
  • same issue for moto g / android 5.1. works withs awesomeplayer. Annoying – unludo Nov 04 '18 at 11:13
33

Create video thumbnail using this

Bitmap thumb = ThumbnailUtils.createVideoThumbnail("file path/url",
                            MediaStore.Images.Thumbnails.MINI_KIND);

and set to videoview

BitmapDrawable bitmapDrawable = new BitmapDrawable(thumb);
            mVideoView.setBackgroundDrawable(bitmapDrawable);
Shijil
  • 2,226
  • 18
  • 33
11

1) Remove your onPrepareListener. I don't know why your video is starting playing after activity creation but onPrepareListener is called after videoView.start().

2) Add an ImageView widget into you layout on top of VideoView. Then set another onPrepareListener like this:

vvVideos.setOnPreparedListener(new OnPreparedListener() {
            public void onPrepared(MediaPlayer mp) {
                previewImage.setVisibility(View.GONE);
            }
        });

I've noticed that onPreparedListener fires too early, so you can use

new Handler().postDelay(Runnable, timeInMilis)

to dismiss preview image.

3) Add OnTouchListener with any gesture detection to you VideoView. Here is an example of what I'm using now:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_video);

    mGestureDetector = new GestureDetector(this, mGestureListener);

    ((VideoView) findViewById(R.id.activity_video_videoview)).setOnTouchListener(mTouchListener);
}
    private OnTouchListener mTouchListener = new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return true;
    }
};
private SimpleOnGestureListener mGestureListener = new SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
    if(mVideoView.isPlaying())
        mVideoView.pause();
    else
        mVideoView.start();
    return true;
};
};

It starts/stops playing by a tap.

Lingviston
  • 5,479
  • 5
  • 35
  • 67
  • Thanks @Lingviston, one more help. I dont want to display some images over the video view. I need to display the starting visual of video. Currently its showing as black color. – Vignesh Jun 17 '13 at 05:41
  • 2
    Try to use seekTo() with any small value like 100-200. – Lingviston Jun 17 '13 at 08:27
  • After implementing Gesture my medicontroller is not working while tapping the video.... – Vignesh Jun 17 '13 at 12:23
8

just seek video to 100 milliseconds it shows thumbnail using seekTo() method

videoView.seekTo(100);
saigopi.me
  • 14,011
  • 2
  • 83
  • 54
5

You can do it with Glide 4.x. It will fetch the first frame of your video show it in an ImageView

add to your build.gradle

implementation 'com.github.bumptech.glide:glide:4.x.x'

and in your Class

GlideApp.with(context)
                .load("your video URL")
                .into(videoImageView);;
Nishant Rajput
  • 2,053
  • 16
  • 28
4

Thought I'd share my solution. The seekTo method works great but only for some devices. Here is my work around. I handle this in the onPrepared method for the onPreparedListener but its up to you.

@Override
public void onPrepared(MediaPlayer mp) {
  MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
  mediaMetadataRetriever.setDataSource(uri.getPath());
  try {
    Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(currentPosition);
    videoView.setBackgroundDrawable(new BitmapDrawable(bitmap));
  } catch (OutOfMemoryError outOfMemoryError) {
    //Not entirely sure if this will ever be thrown but better safe than sorry.
    videoView.seekTo(currentPosition);
  }
}

Now when you play the video you will need to remove this background image like so:

private void play() {
  ...
  videoView.setBackgroundDrawable(null);
  ..
}

Enjoy!

DroidT
  • 3,168
  • 3
  • 31
  • 29
  • Looks it does not work for online video stream, data source should be a local file. Or else IllegalArgumentException would be thrown. – cmoaciopm Aug 17 '16 at 15:41
  • if someone like me is in deep searching ( looking why seekTo is not working previously) and ended here, it won't work. – kolboc Jan 23 '18 at 03:05
2

I know it's an old question, but I needed the same solution and couldn't find the answer anywhere else so I did the solution and I'm sharing the love here:

I just created a little class for it:

   public class LoadFirstVideoFrame implements Runnable {

      private static Handler uiHandler = new Handler(Looper.getMainLooper());
      private VideoView videoView;

      private LoadFirstVideoFrame(VideoView videoView) {
         this.videoView = videoView;
         videoView.start();
         videoView.resume();
         uiHandler.post(this);
      }

      public void stop() {
         videoView = null;
         uiHandler.removeCallbacks(this);
      }

      @Override public void run() {
         if (videoView == null) return;
         if (videoView.isPlaying()) {
            videoView.pause();  
            videoView.seekTo(0);

            videoView = null;
         } else {
            uiHandler.post(this);
         }
      }
   }

it simply asks to start playing and pauses the video back on the first frame as soon as it's actually playing (meaning it loaded the file and it's already rendering it on the SurfaceView).

The important note here is to remember to call stop() on this class so it can properly clean up and not memory leak anything.

I hope it helps.

Budius
  • 39,391
  • 16
  • 102
  • 144
2

I Have Created A ImageView For Thumbnail Like This

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:clickable="true"
    android:focusable="true">

 <VideoView
    android:id="@+id/video_view"
    android:layout_width="match_parent"
    android:layout_height="220dp"/>
<ImageView
    android:id="@+id/videoView_thumbnail"
    android:layout_width="match_parent"
    android:layout_height="220dp"
    android:scaleType="centerCrop"/>

</RelativeLayout>

And Add setOnPreparedListener and setOnCompletionListener in Java Like This Way

  VideoView videoView = (VideoView) view.findViewById(R.id.video_view);
  ImageView thumbnailView=(ImageView)view.findViewById(R.id.videoView_thumbnail);

  Glide.with(getApplicationContext()).load(your_Image_Path).into(thumbnailView);
 //you can add progress dialog here until video is start playing;

    mediaController= new MediaController(getContext());
    mediaController.setAnchorView(videoView);
    videoView.setMediaController(mediaController);
    videoView.setKeepScreenOn(true);
    videoView.setVideoPath(your_video_path);
    videoView.start();         //call this method for auto playing video

    videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            thumbnailView.setVisibility(View.GONE);
 //you can Hide progress dialog here when video is start playing;

        }
    });
    videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            videoView.stopPlayback();
            thumbnailView.setVisibility(View.VISIBLE);

        }
    });

It Works For Me Very Well I Hope Its Usfull For All

Dilip Sonigra
  • 91
  • 1
  • 4
2

very simple !!! you can use glide library.

first add an imageView on videoView and use the code below:

   GlideApp.with(getApplicationContext()).load("empty")
        .thumbnail(GlideApp.with(getApplicationContext()).load("videoURL"))
        .into(imageView);

this code will download an image, and eventually, that leads to less internet consumption.

Nikos Hidalgo
  • 3,666
  • 9
  • 25
  • 39
  • And then I guess on click on the imageView, hide it and start() the videoView. Good solution! – George May 13 '23 at 08:22
0

You can use a @Joshua Pinter's answer to solve the problem. But I want to give you more suggestion about it. You yourself answer that seekTo(100) works instead of seekTo(1). Neither of the two ways is perfect. That is because seekTo(1) would get a black image and the seekTo(100) may got an exception.

I prefer to do like this:

// calculate the during time of the media

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
long time = mediaPlayer.getDuration();

// use a proper number
mVideoView.seekTo(time/2);

If you don't have the backend server, it may be better. Or, if you had a backend server, you can try it in this way.

The thumbnail is calculate by the server, the client just display the image which the backend response. And when it come to server side, you can do a lot of things.

  • Which picture is better? What if the picture is black too?
  • Should the server side generate it? Or should the server side just cache the picture of the media?

If you want to discuss more about the two questions we can discuss them later.

blackdog
  • 2,007
  • 3
  • 25
  • 43
0

Add this in your xml

    `<RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/dimen180"
            android:background="@color/color_bg">

            <com.google.android.exoplayer2.ui.PlayerView
                android:id="@+id/epPlayer"
                android:layout_width="match_parent"
                android:visibility="gone"
                android:layout_height="match_parent"/>

            <FrameLayout
                android:id="@+id/flTv"
                android:layout_width="match_parent"
                android:background="@color/color_bg"
                android:layout_height="match_parent">
                <androidx.appcompat.widget.AppCompatImageView
                    android:id="@+id/ivTv"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:src="@drawable/tv"/>
            </FrameLayout>




            <ProgressBar
                android:id="@+id/pbVideoView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:layout_centerInParent="true"
                android:indeterminate="true" />
        </RelativeLayout>

` for kotlin users

declare variable

private var simpleExoPlayer: ExoPlayer? = null

use this

  simpleExoPlayer = SimpleExoPlayer.Builder(this).build()
    epPlayer.player = simpleExoPlayer
    val dataSourceFactory = DefaultDataSourceFactory(
        this,
        Util.getUserAgent(this, getString(R.string.app_name))
    )
    val videoSource = ProgressiveMediaSource.Factory(dataSourceFactory)
                    .createMediaSource(Uri.parse(it1))
                simpleExoPlayer!!.prepare(videoSource)
                simpleExoPlayer!!.playWhenReady = true
                simpleExoPlayer!!.addListener(object : Player.EventListener{
                    override fun onPlayerStateChanged(
                        playWhenReady: Boolean,
                        playbackState: Int
                    ) {
                        if(playbackState== Player.STATE_READY)
                        {
                            pbVideoView.visibility= View.GONE
                            epPlayer.visibility= View.VISIBLE
                            flTv.visibility= View.GONE
                        }
                        if (playbackState== Player.STATE_BUFFERING)
                        {
                            pbVideoView.visibility= View.VISIBLE
                        }
                    }
                })

I hope it helps.

Prat137
  • 249
  • 2
  • 6
-2

To make your video stop playing when the activity starts just remove the video.start() method.

anothernode
  • 5,100
  • 13
  • 43
  • 62