72

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);
SergioM
  • 1,595
  • 1
  • 15
  • 27
  • 1
    Did you find a solution for your problem ? I got the same situation – M to the K Apr 02 '12 at 18:10
  • I did, the best way to do so was the one below. But the problem persists when you try to remove the view (if the case). It will still flicker. Hopefully is not your case. – SergioM Apr 18 '12 at 00:04
  • Possible duplicate of [android-black screen on displaying video by using VideoView](https://stackoverflow.com/questions/28577704/android-black-screen-on-displaying-video-by-using-videoview) – Roger Alien Sep 05 '17 at 21:05
  • This issue is much older if you check. Thanks – SergioM Sep 12 '17 at 06:58
  • could anyone tell me why it happens? – blackHawk Oct 06 '19 at 03:52
  • Answer for Xamarin Forms: https://stackoverflow.com/questions/60414907/xamarin-forms-android-video-videoview-black-flash-on-page-load-or-back-key-l – Legion Feb 26 '20 at 13:28

25 Answers25

60

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.

wizardlee
  • 881
  • 8
  • 13
  • I applied this with an ImageView on top of the VideoView. when the MEDIA_INFO_VIDEO_RENDERING_START is triggered I hide the ImageView. – mwm Dec 01 '14 at 15:46
  • 1
    just note that MEDIA_INFO_VIDEO_RENDERING_START requires api 17+ – Keke Mar 28 '15 at 15:27
  • 1
    Definately should be the correct answer! +1 my friend ;) – Hugo Sep 17 '15 at 09:01
  • Makes no difference on Android 5.1. – user2966445 Aug 28 '16 at 02:46
  • I tried this and didn't see any flickers on a physical device, but did still see flickers on an emulator (API 23). So it seems that waiting for MEDIA_INFO_VIDEO_RENDERING_START doesn't guarantee anything. I don't know of a better alternative though. – Daniel Lubarov Jul 05 '17 at 21:14
  • Small tip: if you don't want to have a view covering the screen and are happy with showing the view behind you can set the `VideoView`'s alpha to 0, and set it back to 1 on `MEDIA_INFO_VIDEO_RENDERING_START`. Setting visibility to hidden won't work though. – lbarbosa Oct 14 '18 at 17:26
  • this one work for me even without putting `VideoView` inside `FrameLayout` – Dody Rachmat Wicaksono May 07 '20 at 02:19
56

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.

jc_35
  • 1,073
  • 1
  • 9
  • 15
38

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.

M to the K
  • 1,576
  • 3
  • 17
  • 27
  • 4
    This is a very poor workaround because it implies that the an opaque drawable matches the layout. Furthermore, I've discovered that the duration of the flicker varies per device and the first frame is not necessarily showing when `onPrepared()` is called. Disappointing. – Paul Lammertsma Apr 10 '12 at 16:18
  • if it works then who cares if its a 'hack' - in life everything isn't perfect! you could always set a short alpha animation on the framelayout with the placeholder, so that the 'flick' effect is reduced - or play around with something like this.. – Mark Jun 20 '15 at 13:21
  • 3
    but my black screen appears even after onPrepared getting called, what to do for that? – Narendra Singh Dec 02 '15 at 06:19
  • 1
    I still have a black flicker with this solution on Android 5.1. – user2966445 Aug 28 '16 at 02:44
  • 2
    the view still causes flickering. @wizardlee has a correct answer – Ken Zira Sep 16 '18 at 02:50
  • For anyone looking for a Xamarin forms solution: https://stackoverflow.com/questions/60414907/xamarin-forms-android-video-videoview-black-flash-on-page-load-or-back-key-l – Legion Feb 26 '20 at 13:34
27

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

Ravi Bhojani
  • 1,032
  • 1
  • 13
  • 24
  • 2
    For some reason this *improves* the performance, however doesn't completely prevent black flash. Thanks though – Moak Mar 16 '13 at 04:52
  • 1
    This answer helped me and somehow as what @Moak said, it doesn't completely prevent black flash. What i did to prevent it is `if(videoView.isPlaying())` i then set `videoView.setZOrderOnTop(false)` – elL Aug 29 '13 at 06:39
  • it should work for all. At first set videoView.setZOrderOnTop(true); Then set videoView.setZOrderOnTop(true); inside of OnPreparedListener callback. – iamcrypticcoder May 04 '15 at 10:41
22

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

Ahmad Dwaik 'Warlock'
  • 5,953
  • 5
  • 34
  • 56
  • Simple solution. That's the best if you have the possibility to set a color which doesn't fight with you view's style. – andrea.rinaldi Apr 15 '14 at 15:33
  • I had a continuous black screen, only sound played with no video. Color.TRANSPARENT worked for me in the onPreparedListener... Thanks soo much – Janwilx72 Jan 31 '17 at 14:10
18

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.

Siavash
  • 7,583
  • 13
  • 49
  • 69
17

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) {}
}
Carl B
  • 368
  • 3
  • 7
16

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.

emmgfx
  • 573
  • 7
  • 17
4

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.

Paul Burke
  • 25,496
  • 9
  • 66
  • 62
3

Just show a frame from the video as preview.

vSurface.SeekTo(100);
j7nn7k
  • 17,995
  • 19
  • 78
  • 88
3

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.

FutureJJ
  • 2,368
  • 1
  • 19
  • 30
2

Just use VideoView#setBackgroundDrawable(), I think.

  1. initial settings.

    VideoView.setBackgroundDrawable(yourdrawableid);
    
  2. start video

    VideoView.start();
    VideoView.setBackgroundDrawable(0);
    
duggu
  • 37,851
  • 12
  • 116
  • 113
2

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();
}
Gagan
  • 1,497
  • 1
  • 12
  • 27
2

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.

James
  • 4,644
  • 5
  • 37
  • 48
Ramza
  • 21
  • 1
1

Use svVideoView.seekTo(position).

Give Position within 5 (ms).

onPause():
position=svVideoView.getCurrentPosition()

onResume():
svVideoView.seekTo(position);
Mohamed ALOUANE
  • 5,349
  • 6
  • 29
  • 60
Raj
  • 337
  • 1
  • 3
  • 13
1

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);
Aditya
  • 3,525
  • 1
  • 31
  • 38
0

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();
MalaKa
  • 3,734
  • 2
  • 18
  • 31
  • Just `video.setBackgroundColor(Color.WHITE);` before starting the video. Then `video.setBackgroundColor(Color.TRANSPARENT);` when prepared. – Hamzeh Soboh Sep 25 '13 at 09:02
0

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>
OShiffer
  • 1,366
  • 12
  • 27
0

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();
    }
  }
klimat
  • 24,711
  • 7
  • 63
  • 70
  • This is nice solution, but the video is in infinite loop and on some videos there is green line on right edge and black one on bottom (the original video that it is in the project does not have, h.264, mp4). Anyone with this problem? Solution? – Toshe Nov 02 '15 at 15:55
0

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

Vinil Chandran
  • 1,563
  • 1
  • 19
  • 33
0

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.

Fawaz
  • 3,404
  • 3
  • 17
  • 22
0

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

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

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()
oxied
  • 1,773
  • 19
  • 14
-1

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();
Venkata Krishna
  • 1,543
  • 1
  • 11
  • 19