java VideoView播放前后黑闪
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4343350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
VideoView black flash before and after playing
提问by vincentkriek
I have a VideoView which I want to use to play a movieclip. I use it like this to play it and it works.
我有一个 VideoView,我想用它来播放影片剪辑。我像这样使用它来播放它并且它有效。
VideoView vv = new VideoView(this);
vv.setVideoURI(Uri.parse("android.resource://cortex2.hcbj/raw/intro"));
setContentView(vv);
vv.start();
However I see a black flash just before and after the movie clip. The flash in itself isn't a big problem, but the blackness of it is. The background is white, so if the flash is white, or if it dissapears it will be okay.
但是,我在影片剪辑前后看到了黑色闪光。闪光灯本身不是一个大问题,但它的黑度是。背景是白色的,所以如果闪光灯是白色的,或者如果它消失了就可以了。
采纳答案by Thomas Keller
Today I had the same problem and found a very bad and hacky workaround for this nasty problem: I realized that one can set a background color / drawable onto the VideoView
which blends over the video surface and makes it completely hidden. This only works though while the underlying video is still playing, not when it is stopped (neither when it ended normally nor when stopPlayback()
was called), otherwise you'd again see a black flicker. The background must also not be set in the beginning, otherwise the video would be completely hidden right from the start.
今天我遇到了同样的问题,并为这个令人讨厌的问题找到了一个非常糟糕和笨拙的解决方法:我意识到可以设置背景颜色/可绘制到VideoView
混合在视频表面上并使其完全隐藏的背景颜色。这仅在底层视频仍在播放时有效,而不是在它停止时(无论是正常结束还是stopPlayback()
被调用时),否则您会再次看到黑色闪烁。背景也不能在开始时设置,否则视频将从一开始就完全隐藏。
So the only logical step for me was to post a delayed event just before I start the video - and since I know the video length, I let this event happen just a few milliseconds before it ends normally. I took a screenshot of the last frame in VLC and then blended it like this:
所以对我来说唯一合乎逻辑的步骤是在我开始视频之前发布一个延迟事件 - 因为我知道视频长度,我让这个事件在它正常结束前几毫秒发生。我在 VLC 中截取了最后一帧的屏幕截图,然后将其混合如下:
private void startVideo()
{
introVideo.setBackgroundDrawable(null);
introVideo.postDelayed(new Runnable() {
public void run()
{
if (!introVideo.isPlaying())
return;
introVideo.setBackgroundResource(R.drawable.video_still_image);
// other stuff here, for example a custom transition to
// another activity
}
}, 7500); // the video is roughly 8000ms long
introVideo.start();
}
This however was not enough, because when the video actually ended, I still got a short black screen flicker, so I also had to set the still image as background of the container that contained the video (in my case it was the layout of the activity):
然而这还不够,因为当视频真正结束时,我仍然有一个短暂的黑屏闪烁,所以我还必须将静止图像设置为包含视频的容器的背景(在我的例子中它是活动):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/video_still_image">
<VideoView android:id="@+id/introVideo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginTop="-10dip" />
</RelativeLayout>
This activity is rendered in fullscreen and the video is (mostly) scaled to the total screen size (screen 1024x600, video 960x640). I say mostly, because for some unknown reason the layout's background image blends through for about 10px on top. This was the last hack I had to apply to make it work - move the video container -10dip
into the void on top.
此活动以全屏方式呈现,视频(大部分)缩放到总屏幕尺寸(屏幕 1024x600,视频 960x640)。我说的主要是,因为出于某种未知原因,布局的背景图像在顶部混合了大约 10 像素。这是我为使其工作而必须应用的最后一次 hack - 将视频容器移动-10dip
到顶部的空白处。
This now looks awesome on my Galaxy Tab, I don't dare to test it on the SGS2 phone, though...
这现在在我的 Galaxy Tab 上看起来很棒,但我不敢在 SGS2 手机上测试它,不过......
回答by greg7gkb
I ended up having to do something very similar to @tommyd to avoid the black surfaceView flash at the beginning and end of my videos. However, I found that setting/nulling the background drawable for the videoView was not occurring instantly on many phones. There could be about a half-second delay between my call to set the background and when it was actually displayed.
我最终不得不做一些与@tommyd 非常相似的事情,以避免在我的视频开始和结束时出现黑色的 SurfaceView 闪光。但是,我发现在许多手机上设置/清零 videoView 的背景可绘制对象并不是立即发生的。在我调用设置背景和实际显示它之间可能会有大约半秒的延迟。
What I ended up doing was creating a custom SurfaceView that showed a single, solid color, then overlayed this on top of the VideoView and made use of SurfaceView.setZOrderMediaOverlay().
我最终做的是创建一个显示单一纯色的自定义 SurfaceView,然后将其覆盖在 VideoView 之上并使用 SurfaceView.setZOrderMediaOverlay()。
My custom SurfaceView was heavily informed by: http://android-er.blogspot.com/2010/05/android-surfaceview.html
我的自定义 SurfaceView 被大量告知:http: //android-er.blogspot.com/2010/05/android-surfaceview.html
public class SolidSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = SolidSurfaceView.class.getSimpleName();
private SolidSurfaceThread mThread;
private boolean mSurfaceIsValid;
private int mColor;
public SolidSurfaceView(Context context) {
super(context);
init();
}
public SolidSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SolidSurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
Log.verbose(TAG, "init");
getHolder().addCallback(this);
setZOrderMediaOverlay(true);
}
public void setColor(int color) {
mColor = color;
invalidate();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.verbose(TAG, "surfaceCreated");
mSurfaceIsValid = true;
mThread = new SolidSurfaceThread(getHolder(), this);
mThread.setRunning(true);
mThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.verbose(TAG, "surfaceDestroyed");
mSurfaceIsValid = false;
boolean retry = true;
mThread.setRunning(false);
while (retry) {
try {
mThread.join();
retry = false;
}
catch (InterruptedException e) {
Log.warning(TAG, "Thread join interrupted");
}
}
mThread = null;
}
@Override
protected void onDraw(Canvas canvas) {
if ( ! mSurfaceIsValid) {
return;
}
canvas.drawColor(mColor);
}
private static class SolidSurfaceThread extends Thread {
private final SurfaceHolder mSurfaceHolder;
private final SolidSurfaceView mSurfaceView;
private boolean mIsRunning;
public SolidSurfaceThread(SurfaceHolder surfaceHolder, SolidSurfaceView surfaceView) {
mSurfaceHolder = surfaceHolder;
mSurfaceView = surfaceView;
}
public void setRunning(boolean running) {
mIsRunning = running;
}
@Override
public void run() {
while (mIsRunning) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
mSurfaceView.onDraw(c);
}
}
finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
And in the parent activity that hosts the views:
在承载视图的父活动中:
mVideoView = (VideoView)findViewById(R.id.video_view);
mVideoMask = (SolidSurfaceView)findViewById(R.id.video_mask);
mVideoMask.setColor(Color.BLUE);
You can then do things like mVideoMask.setVisibility(View.GONE)
to hide the mask or mVideoMask.setVisibility(View.VISIBLE)
to show the mask (and hide the black-screened VideoView).
然后,您可以执行诸如mVideoMask.setVisibility(View.GONE)
隐藏蒙版或mVideoMask.setVisibility(View.VISIBLE)
显示蒙版(并隐藏黑屏 VideoView)之类的操作。
In my experiments on various phones, this method provided very fast showing/hiding of the video mask, as opposed to setting/nulling the background.
在我对各种手机的实验中,这种方法提供了非常快速的视频蒙版显示/隐藏,而不是设置/清零背景。
回答by Ahmad Dwaik 'Warlock'
i had the same problem and white instead of black was ok for me.. i tried all of solutions above i came up with the following
我有同样的问题,白色而不是黑色对我来说没问题..我尝试了上面的所有解决方案我想出了以下
vv.setBackgroundColor(Color.WHITE);
vv.postDelayed(new Runnable() {
@Override
public void run() {
vv.setVideoURI(videoUri);
}
}, 100);
vv.postDelayed(new Runnable() {
@Override
public void run() {
vv.setBackgroundColor(Color.TRANSPARENT);
}
}, 300);
vv.requestFocus();
vv.start();
and delayed my video 400 ms start fading from white works like a charm for me
并延迟了我的视频 400 毫秒开始从白色开始褪色对我来说就像一种魅力
回答by MattD
My variation on the @tommyd theme:
我对@tommyd 主题的变体:
Set the drawable to a static video frame, then spam the message queue. After some time, clear the drawable so video frames render. Then, before completion, set the static image back.
将 drawable 设置为静态视频帧,然后向消息队列发送垃圾邮件。一段时间后,清除可绘制对象,以便呈现视频帧。然后,在完成之前,将静态图像设置回去。
mMovieView.setBackgroundDrawable(bg);
mMovieView.start();
final int kPollTime= 25;
mMovieView.postDelayed(new Runnable() {
private final int kStartTransitionInThreshold= 50;
private final int kStartTransitionOutThreshold= 250;
private boolean mTransitioned= false;
@Override
public void run() {
if (mMovieView.isPlaying()) {
if (mMovieView.getCurrentPosition() > kStartTransitionInThreshold && !mTransitioned) {
mMovieView.setBackgroundDrawable(null); // clear to video
mTransitioned= true;
}
if (mMovieView.getDuration() - mMovieView.getCurrentPosition() < kStartTransitionOutThreshold)
mMovieView.setBackgroundDrawable(bg);
}
mMovieView.postDelayed(this, kPollTime); // come back in a bit and try again
}
}, kPollTime);
回答by uma
here is simple trick
这是一个简单的技巧
check the condition media player.getCurrentPosition == 0in on prepared listener of video view ,black screen will appear when position is zero so display an image untill the video will load
在准备好的视频视图侦听器中检查条件media player.getCurrentPosition == 0,当位置为零时将出现黑屏,因此显示图像直到视频加载
mycode:
我的代码:
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(final MediaPlayer mediaPlayer) {
mVideoView.start();
runOnUiThread(new Runnable() {
@Override
public void run() {
while (mediaPlayer.isPlaying()) {
Log.d("MainActivity", "position " + mediaPlayer.getCurrentPosition());
if (mediaPlayer.getCurrentPosition() == 0) {
videoStillImageView.setVisibility(View.VISIBLE);
} else {
videoStillImageView.setVisibility(View.GONE);
break;
}
}
}
});
}
}
});
回答by elprl
My workaround for this diabolical bug utilised a blank View with the background colour of choice over the top of the VideoView.
我对这个恶魔般的错误的解决方法使用了一个空白视图,在 VideoView 的顶部选择了背景颜色。
<View
android:id="@+id/blankView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/white" />
then in my code I did this:
然后在我的代码中我这样做了:
video = (VideoView) findViewById(R.id.video);
// set the video URI, passing the vSourse as a URI
video.setVideoURI(Uri.parse(vSource));
video.setZOrderOnTop(false);
SurfaceHolder sh = video.getHolder();
sh.setFormat(PixelFormat.TRANSPARENT);
ctlr = new BCDMediaController(this);
ctlr.setMediaPlayer(video);
video.setMediaController(ctlr);
video.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
closeActivity();
}
});
blankView = findViewById(R.id.blankView);
video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
blankView.postDelayed(new Runnable() {
public void run()
{
blankView.setVisibility(View.GONE);
}
}, 500);
}
});
video.start();
video.requestFocus();
That got rid of the beginning black flash for me. Then for the end black flash, I did this:
这对我来说摆脱了开始的黑色闪光。然后为了结束黑色闪光,我这样做了:
private void closeActivity() {
blankView.setVisibility(View.VISIBLE);
blankView.postDelayed(new Runnable() {
public void run()
{
video.setOnCompletionListener(null);
video.stopPlayback();
video.suspend();
VideoPlayerViewController.this.finish();
}
}, 1);
}
回答by Daniel
Another solution that might work for people who are searching for this question:
另一种可能适用于正在搜索此问题的人的解决方案:
In my case, the video was a resource in the app (that is, I knew everything about it and it wasn't going to change) and its last 500 ms were the same frame, so I ended up doing the following:
在我的例子中,视频是应用程序中的资源(也就是说,我知道关于它的一切,它不会改变)并且它的最后 500 毫秒是同一帧,所以我最终做了以下事情:
mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.splash));
mVideoView.start();
findViewById(android.R.id.content).postDelayed(new WaitForSplashScreenToFinish(), mVideoView.getDuration() - 1000);
and the referenced class is:
并且引用的类是:
private class WaitForSplashScreenToFinish implements Runnable {
@Override
public void run() {
if (mVideoView.isPlaying() && mVideoView.getCurrentPosition() >= mVideoView.getDuration() - 500) {
mVideoView.pause();
// Now do something else, like changing activity
} else {
findViewById(android.R.id.content).postDelayed(this, 100);
}
}
}
Explanation: Immediately after starting the video I create a Runnable and postDelayedit to the root view (android.R.id.content
) to the duration of the video, minus the length at which I'm willing to pause the video (and a generous buffer, because postDelayed isn't guaranteed to play exactlyafter the requested time)
说明:在开始视频后,我立即创建了一个 Runnable 并将其postDelayed到根视图 ( android.R.id.content
) 到视频的持续时间,减去我愿意暂停视频的长度(和一个慷慨的缓冲区,因为 postDelayed 不是t 保证在要求的时间后完全播放)
Then, the runnable checks if the video arrived at its pause-time, if so it pauses it and does whatever else we want it to do. If it doesn't, it runs postDelayed again with itself, for a shortened time (100 ms in my case, but could be shorter)
然后,runnable 检查视频是否到达了它的暂停时间,如果是,它会暂停它并做我们想要它做的任何其他事情。如果没有,它会再次运行 postDelayed,缩短时间(在我的情况下为 100 毫秒,但可能更短)
Granted, this is farfrom being an ideal solution, but it might help someone with a specific problem similar to the one that stumbled me for half a day :)
诚然,这远不是一个理想的解决方案,但它可能会帮助有特定问题的人,类似于让我绊倒半天的问题:)
回答by Subasteve
That flash comes from changing the current content view to another one. You could try adding a VideoView to your layout xml file then referencing it with (VideoView) findViewById(R.id.vid);
instead of new VideoView(this);
and setting the content view to that layout.
该闪光来自将当前内容视图更改为另一个视图。您可以尝试将 VideoView 添加到您的布局 xml 文件,然后使用(VideoView) findViewById(R.id.vid);
而不是引用它new VideoView(this);
并将内容视图设置为该布局。
回答by Manish Singh
Why not using Styling and Themes
为什么不使用样式和主题
Can you try this ? This might help
你能试试这个吗?这可能有帮助
colors.xml
颜色文件
<drawable name="transparent">#00000000</drawable>
styles.xml
样式文件
<style name="Transparent">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">
@android:style/Animation.Translucent
</item>
<item name="android:windowBackground">@drawable/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:colorForeground">#fff</item>
</style>
To set a theme for all the activities of your application, open the AndroidManifest.xml file and edit the tag to include the android:theme attribute with the style name.
要为应用程序的所有活动设置主题,请打开 AndroidManifest.xml 文件并编辑标记以包含 android:theme 属性和样式名称。
<application android:theme="@style/Transparent">
回答by Guillaume Brunerie
Where are you changing the contentView (in which method did you write the four lines of code above)?
你在哪里修改contentView(上面四行代码是用哪个方法写的)?
You should only set the contentView in the onCreate()
method of an Activity
. If you are doing it somewhere else (for exemple in a button's callback), you should start a new activity instead.
您应该只设置内容查看中onCreate()
的方法Activity
。如果您在其他地方执行此操作(例如在按钮的回调中),您应该开始一个新活动。