播放前后的VideoView黑色闪光灯

时间:2010-12-03 07:27:35

标签: java android android-videoview

我有一个VideoView,我想用它来播放一个movieclip。我像这样使用它来播放它并且它有效。

VideoView vv = new VideoView(this);
vv.setVideoURI(Uri.parse("android.resource://cortex2.hcbj/raw/intro"));
setContentView(vv);
vv.start();

但是我在影片剪辑前后看到了黑色闪光。闪光本身不是一个大问题,但它的黑暗是。背景是白色的,所以如果闪光灯是白色的,或者如果它消失了就可以了。

14 个答案:

答案 0 :(得分:8)

今天我遇到了同样的问题,发现这个令人讨厌的问题有一个非常糟糕和黑客的解决方法:我意识到可以将一个背景颜色/可绘制设置到VideoView上,它混合在视频表面上并完全完成隐。这只适用于底层视频仍在播放,而不是在它停止时(无论是正常结束还是调用stopPlayback()时),否则你会再次看到黑色闪烁。背景也不能在开头设置,否则视频将从一开始就完全隐藏。

所以对我来说唯一合乎逻辑的步骤就是在我开始播放视频之前发布延迟事件 - 因为我知道视频长度,所以我让这个事件在正常结束前几毫秒发生。我在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();
}

然而这还不够,因为当视频实际结束时,我仍然会出现短暂的黑屏闪烁,所以我还必须将静止图像设置为包含视频的容器的背景(在我的情况下,它是活动布局):

<?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>

此活动以全屏模式呈现,视频(大部分)缩放到总屏幕尺寸(屏幕1024x600,视频960x640)。我说主要是,因为出于某种未知的原因,布局的背景图像在顶部混合了大约10px。这是我必须申请的最后一次黑客攻击 - 将视频容器-10dip移到顶部的空白处。

这在我的Galaxy Tab上看起来很棒,我不敢在SGS2手机上测试它,不过......

答案 1 :(得分:2)

我最终不得不做一些与@tommyd非常相似的事情,以避免在我的视频的开头和结尾处出现黑色surfaceView flash。但是,我发现在许多手机上没有立即设置/归零videoView的背景可绘制。我设置背景的调用与实际显示的时间之间可能会有大约半秒的延迟。

我最终做的是创建一个自定义SurfaceView,它显示单一的纯色,然后将其叠加在VideoView的顶部,并使用SurfaceView.setZOrderMediaOverlay()。

我的自定义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);
                    }
                }
            }
        }
    }
}

在承载视图的父活动中:

    mVideoView = (VideoView)findViewById(R.id.video_view);
    mVideoMask = (SolidSurfaceView)findViewById(R.id.video_mask);
    mVideoMask.setColor(Color.BLUE);

然后您可以执行mVideoMask.setVisibility(View.GONE)隐藏遮罩或mVideoMask.setVisibility(View.VISIBLE)以显示遮罩(并隐藏黑屏VideoView)等内容。

在我在各种手机上的实验中,这种方法可以非常快速地显示/隐藏视频蒙版,而不是设置/归零背景。

答案 2 :(得分:2)

我有同样的问题,白色而不是黑色对我来说没问题。我尝试了以上所有解决方案我想出了以下

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

并延迟我的视频400毫秒开始从白色褪色工作,像我的魅力

答案 3 :(得分:1)

我对这个恶魔虫的解决方法使用了一个空白视图,其背景颜色选择在VideoView顶部。

<View
        android:id="@+id/blankView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/white" />

然后在我的代码中我这样做了:

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

为我摆脱了一开始的黑色闪光。然后为了结束黑色闪光,我这样做了:

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

答案 4 :(得分:1)

@tommyd主题的变化:

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

答案 5 :(得分:1)

这是简单的技巧

检查条件 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;
                            }
                        }

                    }
                });
            }
        }
    });

答案 6 :(得分:0)

闪存来自将当前内容视图更改为另一个视图。您可以尝试将VideoView添加到布局xml文件中,然后使用(VideoView) findViewById(R.id.vid);而不是new VideoView(this);引用它,并将内容视图设置为该布局。

答案 7 :(得分:0)

为什么不使用样式和主题

你能试试吗?这可能会有所帮助

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>

要为应用程序的所有活动设置主题,请打开AndroidManifest.xml文件并编辑标记以包含带有样式名称的android:theme属性。

<application android:theme="@style/Transparent">

答案 8 :(得分:0)

你在哪里更改contentView(你在哪个方法中编写了上面的四行代码)?

您只应在onCreate()的{​​{1}}方法中设置contentView。如果你在其他地方这样做(例如在按钮的回调中),你应该开始一个新的活动。

答案 9 :(得分:0)

有一种替代方法,您可以使用媒体控制器。这是示例代码

videoView = (VideoView) this.findViewById(R.id.videoView);
MediaController mc = new MediaController(this);
videoView.setMediaController(mc);
videoView.setVideoURI(Uri.parse("http://c421470.r70.cf2.rackcdn.com/video_5983079.m4v"));
videoView.start();
videoView.requestFocus(); 

试试这个。

答案 10 :(得分:0)

另一种可能适用于搜索此问题的人的解决方案:

在我的情况下,视频是应用程序中的资源(也就是说,我知道它的一切并且它不会改变)并且它的最后500毫秒是相同的帧,所以我最终做了以下:

mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.splash));
mVideoView.start();

findViewById(android.R.id.content).postDelayed(new WaitForSplashScreenToFinish(), mVideoView.getDuration() - 1000);

,引用的类是:

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

说明:在启动视频后,我立即创建一个Runnable并将postDelayed创建到根视图(android.R.id.content)到视频的持续时间,减去我愿意暂停的时间长度视频(和一个慷慨的缓冲区,因为postDelayed不能保证在请求的时间之后完全

然后,runnable检查视频是否到达其暂停时间,如果是,它会暂停并执行我们希望它执行的任何操作。如果没有,它会再次运行postDelayed,缩短时间(在我的情况下为100毫秒,但可能更短)

当然,这不是一个理想的解决方案,但它可能会帮助某个特定问题的人类似于那个让我昏迷半天的人:)

答案 11 :(得分:0)

我知道这是一个老问题但是如果你可以向MediaPlayer监听器添加一些代码,那么答案非常简单。事实证明,VideoView的setBackgroundColor改变了前景色(https://groups.google.com/forum/?fromgroups=#!topic/android-developers/B8CEC64qYhQ) 因此,您唯一需要做的就是在setBackgroundColor(Color.WHITE)和setBackgroundColor(Color.TRANSPARENT)之间切换。

答案 12 :(得分:0)

我有同样的问题,这对我有用..

当你想要显示视频时,制作videoView.setZOrderOnTop(false);当你想隐藏视频视图时,只需制作videoView.setZOrderOnTop(true);

答案 13 :(得分:0)

试试这一行。这对我有用。如果(玩家!= NULL)player.release();

@Override
 protected void onDestroy() {
     super.onDestroy();
         player.pause();
     if(player!=null)player.release();
     player = null;
     videoSurface = null;
     controller = null;

 }