如何在播放前在videoview中设置预览图像
Posted
技术标签:
【中文标题】如何在播放前在videoview中设置预览图像【英文标题】:How to set the preview image in videoview before playing 【发布时间】:2013-06-13 05:07:05 【问题描述】:我在我的活动中创建了一个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();
);
现在,在创建 Activity 时视频开始播放。我想让我的活动如下
-
Activity 打开时不应播放视频。
应该显示起始视频图像(当前显示黑色)
它应该只在用户点击视频时播放。
请帮帮我。
【问题讨论】:
【参考方案1】:使用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 在另一个答案中回答了点击时播放它。
【讨论】:
thnaks 伙计,你拯救了我的一天!顺便说一句,调用mVideoView.seekTo(0);
与加载第一帧的结果相同
适用于搭载 Android 5 的 Panasonic CM1。似乎取决于设备上安装的标准视频播放器。
它也适用于 Android 5,如果你去开发者设置并将媒体播放器设置为“AwesomePlayer”(旧的)。这不是生产修复(显然),但它解决了问题所在。
这里是安卓 9。 .seekTo(0);
对我不起作用,但 .seekTo(100);
成功了。谢谢!
我可以确认.seekTo(1)
和seekTo(10)
工作正常。【参考方案2】:
使用此创建视频缩略图
Bitmap thumb = ThumbnailUtils.createVideoThumbnail("file path/url",
MediaStore.Images.Thumbnails.MINI_KIND);
并设置为视频视图
BitmapDrawable bitmapDrawable = new BitmapDrawable(thumb);
mVideoView.setBackgroundDrawable(bitmapDrawable);
【讨论】:
setBakgroundDrawable
已弃用
优秀。效果很棒,考虑到它对视频的解码速度相对较快。我在与视频相同的布局中使用了一个额外的 ImageView,因为 setBakgroundDrawable 已被 VideoView 弃用。
@Apurva 用户设置背景(可绘制背景)。【参考方案3】:
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;
;
;
点击开始/停止播放。
【讨论】:
感谢@Lingviston,再提供一个帮助。我不想在视频视图上显示一些图像。我需要显示视频的起始画面。目前它显示为黑色。 尝试使用 100-200 等任何小的值的 seekTo()。 实施 Gesture 后,我的 medicontroller 在点击视频时无法工作......【参考方案4】:只需将视频搜索到 100 毫秒,它会使用 seekTo() 方法显示缩略图
videoView.seekTo(100);
【讨论】:
【参考方案5】:您可以使用Glide 4.x
完成此操作。它将获取您视频的第一帧并在ImageView
中显示它
添加到您的build.gradle
implementation 'com.github.bumptech.glide:glide:4.x.x'
在你的班级里
GlideApp.with(context)
.load("your video URL")
.into(videoImageView);;
【讨论】:
如果文件是 gilde 中的视频,我们如何添加播放按钮,我不想播放。【参考方案6】:我想我会分享我的解决方案。 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);
..
享受吧!
【讨论】:
看起来对在线视频流不起作用,数据源应该是本地文件。否则会抛出 IllegalArgumentException。 如果像我这样的人在深度搜索中(看看为什么 seekTo 以前没有工作)并在这里结束,它不会工作。【参考方案7】:我知道这是一个老问题,但我需要相同的解决方案,但在其他任何地方都找不到答案,所以我做了解决方案,在这里分享爱:
我刚刚为它创建了一个小类:
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()
,这样它就可以正确清理并且不会发生任何内存泄漏。
希望对你有帮助。
【讨论】:
videoView.pause() 应该在搜索之前发生 @ŁukaszWiśniewski 我已经测试过了,它运行良好。您是否发现此代码有任何问题? 什么时候打电话给stop
@Budius?
这种方法的缺点是它播放视频的时间很短。
@ShajeelAfzal 'onStop()' 您的活动或片段【参考方案8】:
我已经为这样的缩略图创建了一个 ImageView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@color/white"
android:clickable="true"
android:focusable="true">
<VideoView
android:id="@+id/video_view"
android:layout_
android:layout_/>
<ImageView
android:id="@+id/videoView_thumbnail"
android:layout_
android:layout_
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】:非常简单!!! 你可以使用 glide 库。
首先在videoView
上添加imageView
并使用以下代码:
GlideApp.with(getApplicationContext()).load("empty")
.thumbnail(GlideApp.with(getApplicationContext()).load("videoURL"))
.into(imageView);
此代码将下载一张图片,并最终减少互联网消耗。
【讨论】:
【参考方案10】:您可以使用@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);
如果您没有后端服务器,可能会更好。或者,如果你有一个后端服务器,你可以这样尝试。
缩略图由服务器计算,客户端只显示后端响应的图像。当涉及到服务器端时,你可以做很多事情。
哪张图片更好?如果图片也是黑色的怎么办? 应该由服务器端生成吗?还是服务端只缓存媒体图片?如果您想进一步讨论这两个问题,我们可以稍后再讨论。
【讨论】:
【参考方案11】:在你的xml中添加这个
`<RelativeLayout
android:layout_
android:layout_
android:background="@color/color_bg">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/epPlayer"
android:layout_
android:visibility="gone"
android:layout_/>
<FrameLayout
android:id="@+id/flTv"
android:layout_
android:background="@color/color_bg"
android:layout_>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivTv"
android:layout_
android:layout_
android:src="@drawable/tv"/>
</FrameLayout>
<ProgressBar
android:id="@+id/pbVideoView"
android:layout_
android:layout_
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
)
希望对你有帮助。
【讨论】:
【参考方案12】:要让您的视频在活动开始时停止播放,只需删除 video.start()
方法即可。
【讨论】:
以上是关于如何在播放前在videoview中设置预览图像的主要内容,如果未能解决你的问题,请参考以下文章
在 Cypress 中,在测试前在 localStorage 中设置一个令牌