21

ムービークリップの再生に使用したいVideoViewがあります。私はそれをこのように使って演奏し、それは機能します。

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

ただし、ムービークリップの直前と直後に黒いフラッシュが表示されます。フラッシュ自体は大きな問題ではありませんが、その黒さは問題です。背景が白なので、フラッシュが白だったり、消えたりしても大丈夫です。

4

14 に答える 14

11

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電話でテストする勇気はありません...

于 2011-07-29T00:09:05.860 に答える
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ミリ秒遅らせて、白い作品から消え始めました。

于 2013-03-31T13:52:51.360 に答える
2

ビデオの最初と最後にある黒い surfaceView フラッシュを避けるために、@ tommyd と非常によく似たことをしなければならなくなりました。ただし、videoView のバックグラウンド ドローアブルの設定/無効化が、多くの電話で即座に行われないことがわかりました。背景を設定するための呼び出しと、実際に表示されるまでの間に約 0.5 秒の遅延が発生する可能性があります。

私が最終的にやったのは、単一の単色を表示するカスタム 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 を非表示にしたり)することができます。

さまざまな電話での私の実験では、この方法では、背景を設定/無効にするのではなく、ビデオ マスクを非常に高速に表示/非表示にできました。

于 2012-03-08T01:49:45.720 に答える
1

@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);
于 2013-07-25T04:36:28.847 に答える
1

この悪魔的なバグに対する私の回避策は、VideoView の上に背景色を選択した空白の View を利用しました。

<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);    
}
于 2012-02-01T00:45:28.990 に答える
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がないため、十分なバッファー)までルートビュー()にpostDelayedしました。要求された時間の直後android.R.id.contentに再生されることが保証されています

次に、ランナブルは、ビデオが一時停止時間に到着したかどうかをチェックします。到着した場合は、一時停止し、他に実行したいことをすべて実行します。そうでない場合は、postDelayedをそれ自体で再度実行し、時間を短縮します(私の場合、100ミリ秒ですが、もっと短くなる可能性があります)。

確かに、これは理想的な解決策にはほど遠いですが、半日私をつまずかせたような特定の問題を抱えている人を助けるかもしれません:)

于 2012-12-23T15:13:57.980 に答える
0

contentViewをどこで変更しますか(上記の4行のコードをどのメソッドで記述しましたか)?

onCreate()のメソッドでのみcontentViewを設定する必要がありActivityます。他の場所でそれを行っている場合(たとえば、ボタンのコールバックの場合)、代わりに新しいアクティビティを開始する必要があります。

于 2011-07-13T14:26:22.843 に答える
0

私はこれが私のために働いたのと同じ問題を抱えていました..

ビデオを表示したい場合は、videoView.setZOrderOnTop(false); を作成します。ビデオ ビューを非表示にする場合は、videoView.setZOrderOnTop(true); を作成します。

于 2014-01-20T13:18:31.113 に答える
0

これには、メディア コントローラーを使用するという 1 つの代替手段があります。ここにサンプルコードがあります

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

これを試して。

于 2011-07-15T04:46:52.540 に答える
0

スタイリングとテーマを使用しない理由

これを試すことができますか?これは役立つかもしれません

色.xml

<drawable name="transparent">#00000000</drawable>

スタイル.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">
于 2011-07-13T14:21:50.610 に答える
0

そのフラッシュは、現在のコンテンツ ビューを別のビューに変更することによって発生します。レイアウト xml ファイルに VideoView を追加してから、(VideoView) findViewById(R.id.vid);代わりにそれを参照してnew VideoView(this);、コンテンツ ビューをそのレイアウトに設定することができます。

于 2011-04-18T23:20:16.837 に答える
0

古い質問だと思いますが、MediaPlayer リスナーにコードを追加できれば、非常に簡単な答えがあります。VideoView の setBackgroundColor が前景色を変更することが判明しました ( https://groups.google.com/forum/?fromgroups=#!topic/android-developers/B8CEC64qYhQ )。
setBackgroundColor(Color.WHITE) と setBackgroundColor(Color.TRANSPARENT) を切り替えるだけです。

于 2013-05-03T10:40:37.333 に答える