简体   繁体   English

Android VideoView 黑屏

[英]Android VideoView black screen

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.我一直在寻找一种方法来在运行start()方法之前摆脱 VideoView 上令人讨厌的黑色初始屏幕。

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.我还尝试将视频中第一帧的图像放在 VideoView 顶部并将其隐藏在start()方法之后。 Adding an onPrepared listener to start the video and then hide the image.添加一个 onPrepared 侦听器以启动视频,然后隐藏图像。 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.添加 MediaController 根本没有效果。 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.我认为 onPrepared 只是意味着视频已准备好播放,但并不意味着视频已开始播放。 If hide placeholder in onPrepared, the screen still show a black screen.如果在 onPrepared 中隐藏占位符,屏幕仍然显示黑屏。

On my Note3 and Nexus, this solution works well.在我的 Note3 和 Nexus 上,此解决方案运行良好。

I had the same problem on Galaxy tab 2, Android 4.1.1.我在 Galaxy tab 2,Android 4.1.1 上遇到了同样的问题。

Do videoView.setZOrderOnTop(true);videoView.setZOrderOnTop(true); and next videoView.start()和下一个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.它有点hacky,但它可以解决问题。 So basically you need to put your VideoView into a FrameLayout.所以基本上你需要把你的 VideoView 放到一个 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,当您的视频加载并准备好播放时,您将隐藏占位符。

<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在您的活动中,您需要实现 OnPreparedListener 并添加它

//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);当你想显示视频时,制作 videoView.setZOrderOnTop(false); and when you want to hide video, just make videoView.setZOrderOnTop(true);当你想隐藏视频时,只需制作 videoView.setZOrderOnTop(true);

我遇到了同样的问题,我只是使用了 videov.setBackgroundColor(Color.WHITE) 然后 onprepare 我使用了 Color.TRANSPARENT) 对我来说白色仍然比黑色好

By extending a TextureView, I get no black screens in the beginning or end.通过扩展 TextureView,我在开始或结束时都不会出现黑屏。 This is if you want to avoid using ZOrderOnTop(true) .这是如果您想避免使用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.至少两年后,但我希望这会有所帮助。

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.就我而言, onPrepared在黑框消失之前被调用,所以我仍然会看到黑框。

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:所以我所做的是在 xml 中将 VideoView alpha 设置为 0:

android:alpha="0"

and then before I start the video I animate the alpha back to 1:然后在开始播放视频之前,我将 alpha 动画恢复为 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.或者,您可以发布一个延迟的 Runnable 以将 alpha 设置为 1,而不是对其进行动画处理。

This is definitely hacky, but better than overlaying an image (IMO).这绝对是hacky,但比覆盖图像(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 .假设您将东西放入onSaveInstanceState savedInstanceState

只需显示视频中的一帧作为预览。

vSurface.SeekTo(100);

Just use VideoView#setBackgroundDrawable(), I think.我想只需使用 VideoView#setBackgroundDrawable()。

  1. initial settings.初始设置。

     VideoView.setBackgroundDrawable(yourdrawableid);
  2. 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.对于仍在为此寻找答案的人们,在onPrepared中连续调用VideoView.start()VideoView.pause()对我onPrepared 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在 XML 中:VideoView 隐藏在具有白色背景的相对布局后面

    <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并在活动中: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.希望这可以帮助。

Use svVideoView.seekTo(position) .使用svVideoView.seekTo(position)

Give Position within 5 (ms).在 5 (ms) 内给出位置。

onPause():
position=svVideoView.getCurrentPosition()

onResume():
svVideoView.seekTo(position);

It works for me on both Activity and Fragment.它对我的 Activity 和 Fragment 都有效。

VideoView mVideo = (VideoView) findViewById(R.id.yourViewViewId);
          mVideo.setVideoURI(mUri);
          mVideo.setZOrderOnTop(false);

SurfaceHolder surfaceholder = mVideo.getHolder();
surfaceholder.setFormat(PixelFormat.TRANSPARENT);

For me setting the setZOrderOnTop did not completely remove the initial black frame while playing an mp4 video.对我来说,设置setZOrderOnTop并没有完全删除播放 mp4 视频时的初始黑框。 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.我想完全删除最初的黑框,所以我玩了一会儿,发现向前寻找 100 毫秒的视频对我来说很有效。

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.如果有人发现它有帮助,如果我能得到上述为什么有效的确切解释,那仍然会很棒。

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..我已经通过最初设置 BackgroundResource 来处理它,然后在启动视频时,我将背景设置为不可见的颜色..

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:活动_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 .为了避免烦人的闪烁和黑屏问题,我编写了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 .它受益于“占位符解决方案”和(如果您的设备运行 API 级别 14 或更高级别)来自TextureView ,这比VideoView效率高得多。

I wrote article on our blog to cover what it actually does.我在我们的博客上写了一篇文章来介绍它的实际作用。

It's simple to use:使用起来很简单:

Add FrameVideoView to layout:FrameVideoView添加到布局:

<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 :Activity找到它的实例并在onResumeonPause调用相应的方法:

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.我发现其主要原因是使用FrameLayout作为父布局。 Use RelativeLayout as the parent layout of the VideoView使用RelativeLayout作为VideoView的父布局

Modifying @emmgfx's answer worked for me:修改@emmgfx 的答案对我有用:

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. PS:这是科特林。

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 )创建一个带有处理程序的函数,并检查是否 ( videoview.duration > 0 )

if the duration is greater than zero, then set the imageview.visibility to INVISABLE, and immediately follow by handler.removeCallbacks(this)如果持续时间大于零,则将 imageview.visibility 设置为 INVISABLE,然后紧跟 handler.removeCallbacks(this)

Call the above function after you have called videoview.start调用 videoview.start 后调用上面的函数

Code below:代码如下:

fun showVideoView() {有趣的 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 { 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.尝试在大部分白色布局上播放大部分白色视频会以非常明显和烦人的方式显示这些故障,尤其是在 Activity 转换期间。 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 .我设法完全摆脱故障的唯一方法是将来自该线程的一些不同答案和 elprl 在https://stackoverflow.com/a/9089245/3997253 上的答案混合在一起。

Create a solid colour View that covers the VideoView创建一个覆盖 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完成 VideoView 后

// Fade in cover View to hide the VideoView
coverView.animate().alpha(1F)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM