如何在播放前在视频中设置预览图像

时间:2013-06-13 05:07:05

标签: android android-videoview

我在我的活动中创建了VideoView,下面是代码。

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();
        }
    });

现在视频在创建活动时开始播放。我想按照以下方式开展活动

  1. 活动开启时,视频无法播放。
  2. 显示起始视频图像(当前显示黑色)
  3. 只有在用户点击视频时才能播放 请帮帮我。

12 个答案:

答案 0 :(得分:92)

使用seekTo( 1 )显示第一帧。

确保影片已暂停,然后使用seekTo()显示视频的第一帧:

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

mVideoView.setVideoURI( yourVideoPath );

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

注意:我们使用.seekTo( 1 ),因为设置.seekTo( 0 )在Android 9上无效。

@Lingviston在另一个答案中回答了点击时播放的内容。

答案 1 :(得分:26)

使用此

创建视频缩略图
Bitmap thumb = ThumbnailUtils.createVideoThumbnail("file path/url",
                            MediaStore.Images.Thumbnails.MINI_KIND);

并设置为videoview

BitmapDrawable bitmapDrawable = new BitmapDrawable(thumb);
            mVideoView.setBackgroundDrawable(bitmapDrawable);

答案 2 :(得分:9)

1)删除你的onPrepareListener。我不知道为什么你的视频在活动创建后开始播放,但在videoView.start()之后调用onPrepareListener。

2)在VideoView顶部的布局中添加一个ImageView小部件。然后像这样设置另一个onPrepareListener:

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

我注意到onPreparedListener过早触发,所以你可以使用

new Handler().postDelay(Runnable, timeInMilis)

取消预览图片。

3)向您添加带有任何手势检测的OnTouchListener VideoView。这是我现在使用的一个例子:

    @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;
};
};

通过点按开始/停止播放。

答案 3 :(得分:6)

只需使用seekTo()方法

查看视频到100毫秒它就会显示缩略图
try

答案 4 :(得分:4)

您可以使用Glide 4.x执行此操作。它会抓取您视频的第一帧,在ImageView

中显示它

添加到您的build.gradle

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

并在你的班级

GlideApp.with(context)
                .load("your video URL")
                .into(videoImageView);;

答案 5 :(得分:3)

我以为我会分享我的解决方案。 seekTo方法效果很好,但仅适用于某些设备。这是我的工作。我在onPreparedListener的onPrepared方法中处理这个问题,但由你决定。

@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);
  }
}

现在播放视频时,您需要删除此背景图片,如下所示:

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

享受!

答案 6 :(得分:2)

我知道这是一个老问题,但我需要相同的解决方案而无法在其他地方找到答案,所以我做了解决方案,我在这里分享了爱:

我刚为它创建了一个小课程:

   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);
         }
      }
   }

它只是要求开始播放并在第一帧实际播放后暂停视频(意味着它加载了文件并且它已经在SurfaceView上渲染)。

这里重要的一点是要记住在这个类上调用stop(),这样它就可以正常清理,而不是内存泄漏。

我希望它有所帮助。

答案 7 :(得分:1)

非常简单! 您可以使用滑行库。

首先在imageView上添加videoView并使用以下代码:

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

此代码将下载图像,并最终减少互联网使用量。

答案 8 :(得分:0)

我已经为缩略图创建了一个ImageView

<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>

并以这种方式在Java中添加setOnPreparedListener和setOnCompletionListener

  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);

        }
    });

对我来说很好,我希望对所有人都有用

答案 9 :(得分:0)

您可以使用@Joshua Pinter的答案来解决问题。但我想给您更多建议。您自己会回答seekTo(100)可以代替seekTo(1)起作用。两种方式都不完美。这是因为seekTo(1)会得到黑色图像,而seekTo(100)可能会出现异常。

我更喜欢这样:

// 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);

如果没有后端服务器,可能会更好。或者,如果您有后端服务器,则可以通过这种方式尝试。

缩略图是由服务器计算的,客户端只显示后端响应的图像。当涉及到服务器端时,您可以做很多事情。

  • 哪张照片更好?如果图片也是黑色的怎么办?
  • 服务器端应该生成它吗?还是服务器端只缓存媒体图片?

如果您想进一步讨论这两个问题,我们可以在后面讨论。

答案 10 :(得分:0)

将此添加到您的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>

` 对于Kotlin用户

声明变量

private var simpleExoPlayer: ExoPlayer? = null

使用此

  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
                        }
                    }
                })

我希望这会有所帮助。

答案 11 :(得分:-1)

要使视频在活动开始时停止播放,只需删除video.start()方法。