I have been looking for a way to get rid of the nasty black initial screen on a VideoView before the start() method is run.
I have tried with background image on the widget but it doesn't work as expected at all.
I have also tried putting an image of the first frame in the video on top of the VideoView and hiding it after the start() method.
Adding an onPrepared listener to start the video and then hide the image. This works but there is a horrible flicker in the transition and I don't know how to get rid of it.
Adding the MediaController had no effect at all. The problem persists (I still see the black flicker) and I don't want to have the video controls visible at all.
My code looks like this:
VideoView vSurface= (VideoView) findViewById(R.id.surfaceView1);
vSurface.setVideoURI(Uri.parse("android.resource://com.mypackage/" + R.raw.video1));
vSurface.setVisibility(View.VISIBLE);
vSurface.setOnPreparedListener(this);
vSurface.setDrawingCacheEnabled(true);
vSurface.setOnErrorListener(this);
I meet the same problem, and solve it with the accepted solution above plus this:
#Override
public void onPrepared(MediaPlayer mp) {
mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.d(TAG, "onInfo, what = " + what);
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
// video started; hide the placeholder.
placeholder.setVisibility(View.GONE);
return true;
}
return false;
}
});
I think onPrepared just means the video is ready to play, but not means video started playing. If hide placeholder in onPrepared, the screen still show a black screen.
On my Note3 and Nexus, this solution works well.
I had the same problem on Galaxy tab 2, Android 4.1.1.
Do videoView.setZOrderOnTop(true); and next videoView.start()
It works fine for me.
I got the same problem and i found a solution. Its a little bit hacky but it do the trick.
So basically you need to put your VideoView into a FrameLayout.
Over the videoview you need to add another FrameLayout with the background of your video and when your video is loaded and ready to play you hide the placeholder.
<FrameLayout
android:id="#+id/frameLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:layout_marginTop="50dip" >
<VideoView
android:id="#+id/geoloc_anim"
android:layout_width="fill_parent"
android:layout_height="172dip" android:layout_gravity="top|center" android:visibility="visible"/>
<FrameLayout
android:id="#+id/placeholder"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:background="#drawable/fondvert_anim">
</FrameLayout>
In your activity you need to implements OnPreparedListener and add this
//Called when the video is ready to play
public void onPrepared(MediaPlayer mp) {
View placeholder = (View) findViewById(R.id.placeholder);
placeholder.setVisibility(View.GONE);
}
So when the video is ready we hide our placeholder and that trick avoid the black flicker screen.
Hope this help someone.
I had same problem and this has worked for me ..
When you want to show video, make videoView.setZOrderOnTop(false); and when you want to hide video, just make videoView.setZOrderOnTop(true);
I 've got same problem I just used videov.setBackgroundColor(Color.WHITE) and then onprepare i used Color.TRANSPARENT) white is still better than black for me
None of the Above worked for me.
In my case, onPrepared gets called BEFORE the black frame went away, so I would still see the black frame.
I needed a solution where the video appeared shortly after the first frame.
So what I did was set the VideoView alpha to 0 in xml:
android:alpha="0"
and then before I start the video I animate the alpha back to 1:
videoView.animate().alpha(1);
videoView.seekTo(0);
videoView.start();
alternatively, you can just post a delayed Runnable to set the alpha to 1, instead of animating it.
By extending a TextureView, I get no black screens in the beginning or end. This is if you want to avoid using ZOrderOnTop(true).
public class MyVideoView extends TextureView implements TextureView.SurfaceTextureListener {
private MediaPlayer mMediaPlayer;
private Uri mSource;
private MediaPlayer.OnCompletionListener mCompletionListener;
private boolean isLooping = false;
public MyVideoView(Context context) {
this(context, null, 0);
}
public MyVideoView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setSurfaceTextureListener(this);
}
public void setSource(Uri source) {
mSource = source;
}
public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
mCompletionListener = listener;
}
public void setLooping(boolean looping) {
isLooping = looping;
}
#Override
protected void onDetachedFromWindow() {
// release resources on detach
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
super.onDetachedFromWindow();
}
/*
* TextureView.SurfaceTextureListener
*/
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
Surface surface = new Surface(surfaceTexture);
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setLooping(isLooping);
mMediaPlayer.setDataSource(getContext(), mSource);
mMediaPlayer.setSurface(surface);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
mMediaPlayer.reset();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
surface.release();
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
}
This worked for me:
videoView.setBackgroundColor(Color.WHITE); // Your color.
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
videoView.setBackgroundColor(Color.TRANSPARENT);
}
});
At least two years later, but I hope that was helpful.
This is definitely hacky, but better than overlaying an image (IMO).
boolean mRestored = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRestored = savedInstanceState != null;
}
#Override
public void onPrepared(MediaPlayer mp) {
if (!mRestored) vSurface.seekTo(1);
}
Assuming you are putting things into savedInstanceState in onSaveInstanceState.
Just show a frame from the video as preview.
vSurface.SeekTo(100);
Just use VideoView#setBackgroundDrawable(), I think.
initial settings.
VideoView.setBackgroundDrawable(yourdrawableid);
start video
VideoView.start();
VideoView.setBackgroundDrawable(0);
For people still looking for answer for this, calling VideoView.start() and VideoView.pause() in succession inside onPrepared worked for me. I know this may not be the ideal way of achieving this however it might be the one with minimal workaround required in the code. Hope this works for you too.
#Override
public void onPrepared(MediaPlayer mp) {
mVideoView.start();
mVideoView.pause();
}
This one works for me :
In XML : VideoView hide behind a Relative layout with white Background
<VideoView
android:id="#+id/myVideo"
android:layout_below="#+id/logo_top"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
/>
<RelativeLayout
android:id="#+id/mask"
android:background="#FFFFFF"
android:layout_below="#+id/logo_top"
android:layout_centerHorizontal="true"
android:layout_width="200dp" android:layout_height="200dp"
>
</RelativeLayout>
and in Activity : onCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acceuil);
myVideo = (VideoView) findViewById(R.id.myVideo);
mask = (RelativeLayout) findViewById(R.id.mask);
String path = "android.resource://"
+ getPackageName() + "/" + R.raw.anim_normal;
myVideo.setVideoURI(Uri.parse(path));
myVideo.start();
}
onStart :
public void onStart() {
final long time = System.currentTimeMillis();
super.onStart();
new CountDownTimer(5000, 100) {
#Override
public void onTick(long l) {
long time2 = System.currentTimeMillis();
if((time2 - time) > 500) {
mask.setVisibility(View.GONE);
}
}
}.start();
Hope this helps.
For me setting the setZOrderOnTop did not completely remove the initial black frame while playing an mp4 video. It, however, did reduce the time for which the black frame appears. I wanted to remove the initial black frame completely, so I played around and found that seeking the video forward by 100ms did the trick for me.
As a note, I am using the video in a loop, so if you do not want to loop the video just remove
mp.isLooping = true
Following is the snippet which I used to fix the issue:
val path = "android.resource://" + packageName + "/" + R.raw.my_video
videoView.setVideoURI(Uri.parse(path))
videoView.setZOrderOnTop(true)
videoView.seekTo(100)
videoView.start()
videoView.setOnPreparedListener { mp ->
videoView.setZOrderOnTop(false)
mp.isLooping = true // Loops the video
}
It would still be great if I get an exact explanation of why the above worked if someone finds it helpful.
Use svVideoView.seekTo(position).
Give Position within 5 (ms).
onPause():
position=svVideoView.getCurrentPosition()
onResume():
svVideoView.seekTo(position);
It works for me on both Activity and Fragment.
VideoView mVideo = (VideoView) findViewById(R.id.yourViewViewId);
mVideo.setVideoURI(mUri);
mVideo.setZOrderOnTop(false);
SurfaceHolder surfaceholder = mVideo.getHolder();
surfaceholder.setFormat(PixelFormat.TRANSPARENT);
It's a little late for this answer, but maybe other users have the same problem and find this question..
I have dealt with it, by setting a BackgroundResource initially and then, when starting the video, i have set the background to an invisible color..
VideoView myView = findViewById(R.id.my_view);
myView.setBackgroundResource(R.drawable.some_resource);
// some stuff
// this is when starting the video
myView.setVideoUri(someUri);
// also set MediaController somewhere...
//...
// now set the backgroundcolor to be not visible (first val of Color.argb(..) is the alpha)
myView.setBackGroundColor(Color.argb(0, 0, 0, 0));
//...
myView.start();
This is a nice solution:
package com.example.videoviewpractice;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.MediaController;
import android.widget.VideoView;
public class MainActivity extends Activity {
VideoView myVideoView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVideo();
}
private void initVideo() {
myVideoView = (VideoView) findViewById(R.id.videoView1);
String url = "http://mtc.cdn.vine.co/r/videos/3DF00EB7001110633055418310656_1e50d6d9a65.3.2.mp4?" +
"versionId=KVMUFFGqe6rYRrGKgl8hxL6eakVAErPy";
myVideoView.setVideoURI(Uri.parse(url));
myVideoView.setMediaController(new MediaController(this));
myVideoView.requestFocus();
}
public void gone(View v){
myVideoView.setZOrderOnTop(true);
View placeholder = (View) findViewById(R.id.placeholder);
placeholder.setVisibility(View.GONE);
myVideoView.start();
}
}
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<FrameLayout
android:id="#+id/frameLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:layout_marginTop="50dip" >
<VideoView
android:id="#+id/videoView1"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_gravity="top|center"
android:visibility="visible" />
<FrameLayout
android:id="#+id/placeholder"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_gravity="top|center"
android:background="#drawable/ic_launcher"
android:onClick="gone" >
</FrameLayout>
</FrameLayout>
</LinearLayout>
To avoid annoying flickering and black screen issues I wrote FrameVideoView.
It takes benefits from 'placeholder solution' and (if your device is running API level 14 or higher) from TextureView, which is much more efficient than VideoView.
I wrote article on our blog to cover what it actually does.
It's simple to use:
Add FrameVideoView to layout:
<mateuszklimek.framevideoview.FrameVideoView
android:id="#+id/frame_video_view"
android:layout_width="#dimen/video_width"
android:layout_height="#dimen/video_height"
/>
find its instance in Activity and call corresponding methods in onResume and onPause:
public class SampleActivity extends Activity {
private FrameVideoView videoView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple);
String uriString = "android.resource://" + getPackageName() + "/" + R.raw.movie;
videoView = (FrameVideoView) findViewById(R.id.frame_video_view);
videoView.setup(Uri.parse(uriString), Color.GREEN);
}
#Override
protected void onResume() {
super.onResume();
videoView.onResume();
}
#Override
protected void onPause() {
videoView.onPause();
super.onPause();
}
}
I had the same issue. I found that the main reason for that was the use of FrameLayout as the parent layout. Use RelativeLayout as the parent layout of the VideoView
Modifying #emmgfx's answer worked for me:
videoView.setBackgroundColor(Color.WHITE)
videoView.start()
Timer().schedule(100){
videoView?.setBackgroundColor(Color.TRANSPARENT)
}
Trick is to delay the video view untill video loads.
PS : It's kotlin.
I found a great solution to this problem. ( in Kotlin )
Create an imageview over top of your videoview.
Create a function with a handler, and check if ( videoview.duration > 0 )
if the duration is greater than zero, then set the imageview.visibility to INVISABLE, and immediately follow by handler.removeCallbacks(this)
Call the above function after you have called videoview.start
Code below:
fun showVideoView() {
val handler = Handler()
handler.postDelayed(object : Runnable {
override fun run() {
try {
if (videoplayer_topthree.currentPosition > 0) {
videoview_topthreeloadingimage.visibility = View.INVISIBLE
videoview_topthreeprogressbar.visibility = View.VISIBLE
videoview_topthreefullname.visibility = View.VISIBLE
videoview_topthreeviews.visibility = View.VISIBLE
videoview_topthreedate.visibility = View.VISIBLE
videoview_topthreedescription.visibility = View.VISIBLE
videoview_topthreedimview.visibility = View.VISIBLE
handler.removeCallbacks(this)
}
handler.postDelayed(this, 250)
} catch (e: Exception) {
println("SHOW VIDEOVIEW CATCH WAS CAUGHT")
}
}
}, 0)
}
and this is where I call this function..
videoplayer_topthree.setOnPreparedListener {
prepareSizing(it)
initializeProgressBar()
showVideoView()
}
Trying to play a mostly white video on a mostly white layout shows these glitches in a very obvious and annoying way, particularly during Activity transitions. The only way I managed to completely get rid of the glitches was to mash together a few different answers from this thread and elprl's answer at https://stackoverflow.com/a/9089245/3997253.
Create a solid colour View that covers the VideoView
<View
android:id="#+id/coverView"
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In onCreate
...
coverView = findViewById(R.id.coverView)
videoView = findViewById(R.id.videoView)
videoView.setZOrderOnTop(false)
val surfaceHolder = videoView.holder
surfaceHolder.setFormat(PixelFormat.TRANSPARENT)
In onStart
...
videoView.setOnPreparedListener { mp ->
// Fade out cover View to show VideoView once rendering has started
mp.setOnInfoListener { _, what, _ ->
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
coverView.animate().alpha(0F)
return#setOnInfoListener true
}
return#setOnInfoListener false
}
mp.isLooping = true
videoView.start()
videoView.requestFocus()
}
When done with the VideoView
// Fade in cover View to hide the VideoView
coverView.animate().alpha(1F)
Only this worked for me:
fun VideoView.startWithRawFile(rawFileResId: Int, delay: Long = 0, backgroundColorResId: Int = R.color.white) {
setBackgroundResource(backgroundColorResId)
setVideoURI(uriToRawFile(rawFileResId))
setOnPreparedListener {
postDelayed(delay) {
start()
// replace 200 with your value according to your video file content:
postDelayed(200) { setBackgroundResource(R.color.transparent) }
}
}
}
// additional:
fun uriToRawFile(rawFileResId: Int) = Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE).authority(app().packageName).appendPath("$rawFileResId").build()
fun postDelayed(ms: Long, runnable: () -> Unit) = if (ms > 0) Handler(Looper.getMainLooper()).postDelayed(runnable, ms)
else runnable.invoke()
see this
VideoView videoView = (VideoView) findViewById(R.id.VideoView);
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(videoView);
Uri video = Uri.parse("android.resource://your_package_name/"+R.raw.monkeysonthebed_video);
videoView.setMediaController(mediaController);
videoView.setVideoURI(video);
videoView.start();
Related
Good day all,
Please i'm using videoview to play a local video file, and i attached the mediacontroller, video plays ok, but no matter the setting i use, the media controller doesn't show, when i touch the device screen:
My code below:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Preview);
this.Window.SetFlags(WindowManagerFlags.KeepScreenOn, WindowManagerFlags.KeepScreenOn);
videoView = FindViewById<VideoView>(Resource.Id.videoPreView);
mediaController = new MediaController(this, true);
mediaController.SetAnchorView(videoView);
videoView.SetMediaController(mediaController);
}
protected override void OnStart()
{
base.OnStart();
videoView.Prepared += OnVideoPlayerPrepared;
Play("MyVids/PreviewCourse.mp4");
}
protected override void OnStop()
{
base.OnStop();
videoView.Prepared -= OnVideoPlayerPrepared;
}
private void OnVideoPlayerPrepared(object sender, EventArgs e)
{
mediaController.SetAnchorView(videoView);
//show media controls for 3 seconds when video starts to play
mediaController.Show(3000);
}
And this is my axml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/videoPreView"
android:layout_centerInParent="true" />
Note: My videos are 480 by 360 in dimension
Thanks for your help
Well eventually, i had to create the buttons for pause/play, forward, and rewind manually.
player.pause();
player.play();
player.SeekTo(CurrentPosition + 5000); //for forward 5 secs
player.SeekTo(CurrentPosition - 5000) //to rewind
Didn't know it was that easy
For those who want to create there's manually
I'm struggling to play a video from Assets with a VideoView and a MediaPlayer.
Build version : android 6.0.1 Marshmallow API 23
Debug Device : NVIDIA SHIELD Tablet K1
The issue : my VideoView seems to not create a surface, since the function "SurfaceCreated" is never called during debug.
Actual result : when the activity is loaded, the screen is grey and I can hear the correct sound of the video.
Here is my code :
public class VideoTestActivity : Activity, MediaPlayer.IOnPreparedListener, ISurfaceHolderCallback
{
MediaPlayer player;
VideoView _myVideoView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.VideoTest);
player = new MediaPlayer();
_myVideoView = FindViewById<VideoView>(Resource.Id.video);
_myVideoView.Start();
_myVideoView.SetZOrderOnTop(true); // tried from Q&A, display a grey screen
var descriptor = Assets.OpenFd("video.mp4");// the data is correctly loaded
player.SetDataSource(descriptor.FileDescriptor, descriptor.StartOffset, descriptor.Length);
player.Prepare();
player.Start();
}
public void OnPrepared(MediaPlayer mp)
{
throw new NotImplementedException();
}
public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
{
throw new NotImplementedException();
}
public void SurfaceCreated(ISurfaceHolder holder)
{
player.SetDisplay(_myVideoView.Holder); // never called
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
throw new NotImplementedException();
}
}
And here is my axml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:p1="http://schemas.android.com/apk/res/android"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="match_parent"
p1:id="#+id/relativeLayout1">
<VideoView
p1:layout_width="fill_parent"
p1:layout_height="fill_parent"
p1:id="#+id/video"/>
</RelativeLayout>
What I have tried/checked :
my VideoView has a widht/height different from 0
the descriptor is correctly loaded
SetZOrderOnTop() has been called after Start()
the videoView is correctly loaded by FindViewById()
I'm still searching for an anwser, but since I have checked every post-related on stackOverflow, I opened this post.
Thanks for your time and knowledge.
Ok so finally i found a solution to play my video, but none to load the Surface.
Creating a raw folder was the solution.
here is the new code (other fields from the previous one are blank):
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.VideoTest);
VideoView view = (VideoView)FindViewById(Resource.Id.videoPacificRim);
String path = "android.resource://" + PackageName + "/" + Resource.Raw.pacificrim_file;
view.SetVideoURI(Android.Net.Uri.Parse(path));
view.Start();
}
I close the subject, even if the original question is not answered.
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
Video should not play when the activity gets open.
It shoud display the starting video image(currently its displaying black color)
It should play only when the user click on the video.
please help me.
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.
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);
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.
just seek video to 100 milliseconds it shows thumbnail using seekTo() method
videoView.seekTo(100);
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);;
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!
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.
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
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.
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.
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.
To make your video stop playing when the activity starts just remove the video.start() method.
I have a problem in running a video in Samsung S3(Android 4.1.1), the issue seems to be because the videoview is on a fragment because if I put it on and activity, it works.
Also I found out that if I turn on the GPU hardware acceleration on, the video works.
I have also a game made by drawing on a SurfaceView and that view doesn't work as well(only with GPU on)... The rest of the app content is displayed as it supposed to (buttons and other layouts).
I tested the app on Nexus S and on the emulator and it works fine, also on other devices..
Does anyone know what the problem could be?
Thank you!
And here is the code:
public class VideoFragment extends Fragment implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
private Video mVideo;
private VideoView mVideoView;
// The video position
private int mPosition;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.screen_video, container, false);
mVideoView = (VideoView) fragmentView.findViewById(R.id.VideoView);
return fragmentView;
}
#Override
public void onPause() {
super.onPause();
// Pause the video if it is playing
if (mVideoView.isPlaying()) {
mVideoView.pause();
}
// Save the current video position
mPosition = mVideoView.getCurrentPosition();
}
#Override
public void onResume() {
super.onResume();
mVideoView.setOnCompletionListener(this);
mVideoView.setOnPreparedListener(this);
mVideoView.setOnErrorListener(this);
mVideoView.setKeepScreenOn(true);
// Initialize the media controller
MediaController mediaController = new MediaController(getActivity());
mediaController.setMediaPlayer(mVideoView);
// Set-up the video view
mVideoView.setMediaController(mediaController);
mVideoView.requestFocus();
mVideoView.setVideoPath(mVideo.getUrl());
if (mVideoView != null) {
// Restore the video position
mVideoView.seekTo(mPosition);
mVideoView.requestFocus();
}
}
#Override
public void onDestroy() {
super.onDestroy();
// Clean-up
if (mVideoView != null) {
mVideoView.stopPlayback();
mVideoView = null;
}
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
Log.e("VIDEO PLAY", "end video play");
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
// Start the video view
mediaPlayer.start();
Log.e("VIDEO PLAY", "video ready for playback");
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
Log.e("VIDEO PLAY", "error: " + i);
return true;
}
}
I don't think it's something related to context(Application or Activity).. because on all other devices the Video and the games are displayed..
Thanks for the help!
I have a similar problem, and i solved it changing:
MediaController mediaController = new MediaController(getActivity().getApplicationContext());
to this (In a fragmet):
MediaController mediaController = new MediaController(getActivity());
Hope this helps,...
EDIT
Look at this class
http://code.google.com/p/sinaweibo-honeycomb/source/browse/branches/sinaweibo-merged/src/com/lenovo/dll/SinaWeibo/VideoFragment.java?r=71
If hardware acceleration fixes your issue then I would enable it for that view/window on that device.
In general I've found that when code works on one device but not another it is typically caused by one of the following problems:
Bug in the manufacturer's API implementation
Different interpretation of the API by the manufacturer
Concurrency problem (e.g. race condition, improper synchronization) in your own code that happens to trigger more frequently on a particular device
As far as I can tell you seem to be using the UI thread appropriately so I would imagine your issue falls into one of the first two categories and you'll just need to work around it.
Move MediaController mediaController = new MediaController(getActivity()) from onResume() to onCreateView.
This below activity works fine but the mediaController display only if I click on the screen. And the second problem is the media controller display only for 3 sec. what should I do to remove this problem?
public class PlayingActivity extends Activity
{
private VideoView mVideoView;
private EditText mPath;
MediaController mediaController;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.playingactivity);
mPath = (EditText) findViewById(R.id.path);
mPath.setText(GlobalVariable.getstrEmail());
mVideoView = (VideoView) findViewById(R.id.surface_view);
Uri uri = Uri.parse("/sdcard/download/test.mp3");
mediaController = new MediaController(this);
mediaController.findFocus();
mediaController.setEnabled(true);
mediaController.show(0);
mediaController.setAnchorView(mVideoView);
mVideoView.setMediaController(mediaController);
mVideoView.setVideoURI(uri);
mVideoView.start();
}
}
mediaController.requestFocus();
will make it display as soon as the video starts ( without requiring the click)
and
mVideoView.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mediaController.show(0);
}
});
Will keep it on the screen.
Hope it helps
Requesting focus or specifying 0 in show method never worked for me.
The problem is that MediaController class has default timeout of 3000ms or 3seconds. And its show() method replaces our given parameter to its default parameter. Its a stupid bug resulting from untested code at Google.
We need to implement a lousy workaround of replacing the default value by desired value.
Try the below code. It should work.
mediaControls = new MediaController(getActivity()){
#Override
public void show (int timeout){
if(timeout == 3000) timeout = 20000; //Set to desired number
super.show(timeout);
}
};
mVideoView.setMediaController(mediaControls);
Neo's suggestions are perfect. But I would like to add "mp.start()" to onPrepared(MediaPlayer mp) method, without which the media file won't start playing.
There are two main problem in MediaController:
auto hide is 3s by default
Tapping on the video shows/hide the control bar
For the first part it's easly fixed changing the default timeout value of start to zero (zero means indefinite,it is used internally as the video starts) like this:
mediaController = new MediaController(this){
#Override
public void show() {
super.show(0);//Default no auto hide timeout
}
};
The second problem is a little tricky because the click handler is declared as private and final so we do not have any control on that.
My solution is to use another function to set visibility and disable the hide function like this:
mediaController = new MediaController(this){
#Override
public void show() {
super.show(0);//Default no auto hide timeout
}
#Override
public void hide() {
//DOES NOTHING
}
void setVisible(boolean visible){//USE THIS FUNCTION INSTEAD
if(visible)
super.show();
else
super.hide();
}
};
You can also add a variable to re-enable standard functionality if visibility is set to false like so:
mediaController = new MediaController(this){
private boolean forceVisible=false;
#Override
public void show() {
super.show(0);//Default no auto hide timeout
}
#Override
public void hide() {
if(!forceVisible)super.hide();
}
void setVisible(boolean visible){
forceVisible=visible;
if(visible)
super.show();
else
super.hide();
}
};