视频查看播放前后的黑色闪光

2022-09-02 04:33:07

我有一个视频视图,我想用它来播放电影剪辑。我像这样使用它来玩它,它的工作原理。

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

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


答案 1

今天,我遇到了同样的问题,并发现了一个非常糟糕和黑客的解决方法来解决这个令人讨厌的问题:我意识到可以设置一个背景颜色/可绘制到视频表面上混合并使其完全隐藏。这仅在基础视频仍在播放时有效,而不是在停止时(无论是在正常结束时还是在被调用时),否则您将再次看到黑色闪烁。背景也不得在开始时设置,否则视频将从一开始就完全隐藏。VideoViewstopPlayback()

因此,对我来说,唯一合乎逻辑的步骤是在我开始视频之前发布一个延迟事件 - 并且由于我知道视频长度,因此我让此事件发生在正常结束前几毫秒。我截取了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选项卡上看起来很棒,我不敢在SGS2手机上进行测试,但是......


答案 2

我最终不得不做一些与@tommyd非常相似的事情,以避免在视频开头和结尾出现黑色surfaceView闪光灯。但是,我发现在许多手机上,设置/取消视频视图的背景可绘制对象并没有立即发生。在我设置背景的调用与实际显示背景之间可能有大约半秒钟的延迟。

我最终做的是创建一个自定义的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);

然后,您可以执行隐藏蒙版或显示蒙版(以及隐藏黑屏 VideoView)等操作。mVideoMask.setVisibility(View.GONE)mVideoMask.setVisibility(View.VISIBLE)

在我对各种手机的实验中,这种方法提供了非常快速的视频掩码显示/隐藏,而不是设置/清空背景。


推荐