Черная вспышка VideoView до и после воспроизведения

У меня есть VideoView, который я хочу использовать для воспроизведения мувиклипа. Я использую его так, чтобы играть, и он работает.

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

Однако я вижу черную вспышку до и после клипа. Вспышка сама по себе не является большой проблемой, но ее чернота. Фон белый, поэтому, если вспышка белая, или если она исчезнет, ​​все будет хорошо.

Ответы

Ответ 1

Сегодня у меня была та же проблема, и я нашел очень плохой и взломанный обходной путь для этой неприятной проблемы: я понял, что можно установить цвет фона/нарисовать на 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). Я говорю в основном, потому что по какой-то неизвестной причине макет фонового изображения смещается примерно на 10 пикселей поверх. Это был последний взлом, который я должен был применить, чтобы заставить его работать - переместите видеоконтент -10dip в верхнюю часть void.

Теперь это выглядит потрясающе на моей Galaxy Tab, я не осмеливаюсь проверить его на телефоне SGS2, хотя...

Ответ 2

В итоге мне пришлось сделать что-то очень похожее на @tommyd, чтобы избежать появления черной flash-поверхности в начале и конце моих видео. Тем не менее, я обнаружил, что установка/обнуление фонового рисунка для видеообзора не происходит мгновенно на многих телефонах. Между моим вызовом может быть около полусекундной задержки, чтобы установить фон и когда он был фактически отображен.

В результате я создал пользовательский 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), чтобы показать маску (и скрыть черно-белое видеоизображение).

В моих экспериментах на разных телефонах этот метод обеспечивал очень быстрое отображение/скрытие видеомаски, в отличие от установки/обнуления фона.

Ответ 3

У меня была та же проблема, и белый вместо черного был в порядке для меня.. Я пробовал все решения выше, я придумал следующие

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 мс начало замирания от белых работает как прелесть для меня

Ответ 4

В моем обходном пути для этой дьявольской ошибки использовался пустой вид с выбранным цветом фона в верхней части 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);    
}

Если это поможет, проголосуйте за этот ответ.

Ответ 5

Эта вспышка возникает из-за изменения текущего представления контента на другое. Вы можете попробовать добавить VideoView в свой XML файл макета, а затем ссылаться на него с помощью (VideoView) findViewById(R.id.vid); вместо new VideoView(this); и настроить представление содержимого на этот макет.

Ответ 6

Почему бы не использовать стили и темы

Вы можете попробовать? Это может помочь

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

Ответ 7

Где вы меняете contentView (в каком методе вы пишете четыре строки кода выше)?

Вы должны установить contentView только в onCreate() методе Activity. Если вы делаете это где-то еще (например, в обратном вызове кнопок), вы должны начать новую деятельность.

Ответ 8

Существует одна альтернатива, для которой вы используете медиаконтроллер. Вот пример кода

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

Попробуйте это.

Ответ 9

Другое решение, которое может работать для людей, которые ищут этот вопрос:

В моем случае видео было ресурсом в приложении (то есть, я знал все об этом, и он не собирался меняться), а его последние 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 мс в моем случае, но может быть короче).

Конечно, это далеко не идеальное решение, но это может помочь кому-то с конкретной проблемой, подобной той, которая наткнулась на меня на полдня:)

Ответ 10

Я знаю старый вопрос, но если вы можете добавить код в прослушиватели MediaPlayer, есть очень простой ответ. Оказалось, что setBackgroundColor для VideoView изменяет цвет переднего плана (https://groups.google.com/forum/?fromgroups=#!topic/android-developers/B8CEC64qYhQ).
Так что единственное, что вам нужно сделать, это переключение между setBackgroundColor (Color.WHITE) и setBackgroundColor (Color.TRANSPARENT).

Ответ 11

Мое изменение в теме @tommyd:

Установите для рисования статический видеокадр, а затем спам очереди сообщений. По прошествии некоторого времени очистите выталкиваемые видеофрагменты. Затем, перед завершением, установите статическое изображение обратно.

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

Ответ 12

У меня была такая же проблема, что это сработало для меня.

Если вы хотите показать видео, сделайте videoView.setZOrderOnTop(false); и когда вы хотите скрыть просмотр видео, просто сделайте videoView.setZOrderOnTop(true);

Ответ 13

Попробуйте эту строку. Это работало для меня. если (игрок!= NULL) player.release();

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

 }

Ответ 14

вот простой трюк

проверьте условие 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;
                            }
                        }

                    }
                });
            }
        }
    });