簡體   English   中英

Android VideoView 黑屏

[英]Android VideoView black screen

我一直在尋找一種方法來在運行start()方法之前擺脫 VideoView 上令人討厭的黑色初始屏幕。

我已經嘗試在小部件上使用背景圖像,但它根本沒有按預期工作。 我還嘗試將視頻中第一幀的圖像放在 VideoView 頂部並將其隱藏在start()方法之后。 添加一個 onPrepared 偵聽器以啟動視頻,然后隱藏圖像。 這有效,但在過渡中有一個可怕的閃爍,我不知道如何擺脫它。


添加 MediaController 根本沒有效果。 問題仍然存在(我仍然看到黑色閃爍),我根本不想讓視頻控件可見。 我的代碼如下所示:

    VideoView vSurface= (VideoView) findViewById(R.id.surfaceView1);
    vSurface.setVideoURI(Uri.parse("android.resource://com.mypackage/" + R.raw.video1));
    vSurface.setVisibility(View.VISIBLE);
    vSurface.setOnPreparedListener(this);
    vSurface.setDrawingCacheEnabled(true);
    vSurface.setOnErrorListener(this);

我遇到了同樣的問題,並用上面接受的解決方案解決了這個問題:

  @Override
  public void onPrepared(MediaPlayer mp) {
    mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
      @Override
      public boolean onInfo(MediaPlayer mp, int what, int extra) {
        Log.d(TAG, "onInfo, what = " + what);
        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
          // video started; hide the placeholder.
          placeholder.setVisibility(View.GONE);
          return true;
        }
        return false;
      }
    });

我認為 onPrepared 只是意味着視頻已准備好播放,但並不意味着視頻已開始播放。 如果在 onPrepared 中隱藏占位符,屏幕仍然顯示黑屏。

在我的 Note3 和 Nexus 上,此解決方案運行良好。

我在 Galaxy tab 2,Android 4.1.1 上遇到了同樣的問題。

videoView.setZOrderOnTop(true); 和下一個videoView.start()

這對我來說可以。

我遇到了同樣的問題,我找到了解決方案。 它有點hacky,但它可以解決問題。 所以基本上你需要把你的 VideoView 放到一個 FrameLayout 中。 在視頻視圖上,您​​需要添加另一個帶有視頻背景的 FrameLayout,當您的視頻加載並准備好播放時,您將隱藏占位符。

<FrameLayout
  android:id="@+id/frameLayout1"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_gravity="center"
  android:layout_marginTop="50dip" >

  <VideoView
    android:id="@+id/geoloc_anim"
    android:layout_width="fill_parent"
    android:layout_height="172dip" android:layout_gravity="top|center" android:visibility="visible"/>

  <FrameLayout
      android:id="@+id/placeholder"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent" android:background="@drawable/fondvert_anim">
  </FrameLayout>

在您的活動中,您需要實現 OnPreparedListener 並添加它

//Called when the video is ready to play
public void onPrepared(MediaPlayer mp) {

    View placeholder = (View) findViewById(R.id.placeholder);

    placeholder.setVisibility(View.GONE);
}

所以當視頻准備好時,我們隱藏我們的占位符,這個技巧避免了黑色閃爍的屏幕。

希望這有助於某人。

我有同樣的問題,這對我有用..

當你想顯示視頻時,制作 videoView.setZOrderOnTop(false); 當你想隱藏視頻時,只需制作 videoView.setZOrderOnTop(true);

我遇到了同樣的問題,我只是使用了 videov.setBackgroundColor(Color.WHITE) 然后 onprepare 我使用了 Color.TRANSPARENT) 對我來說白色仍然比黑色好

通過擴展 TextureView,我在開始或結束時都不會出現黑屏。 這是如果您想避免使用ZOrderOnTop(true)

public class MyVideoView extends TextureView implements TextureView.SurfaceTextureListener {
  private MediaPlayer mMediaPlayer;
  private Uri mSource;
  private MediaPlayer.OnCompletionListener mCompletionListener;
  private boolean isLooping = false;


  public MyVideoView(Context context) {
      this(context, null, 0);
  }

  public MyVideoView(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
  }

  public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      setSurfaceTextureListener(this);
  }

  public void setSource(Uri source) {
      mSource = source;
  }

  public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
      mCompletionListener = listener;
  }

  public void setLooping(boolean looping) {
     isLooping = looping;
  }

  @Override
  protected void onDetachedFromWindow() {
     // release resources on detach
     if (mMediaPlayer != null) {
         mMediaPlayer.release();
         mMediaPlayer = null;
     }
     super.onDetachedFromWindow();
   }

   /*
    * TextureView.SurfaceTextureListener
    */
    @Override
   public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
     Surface surface = new Surface(surfaceTexture);
     try {
         mMediaPlayer = new MediaPlayer();
         mMediaPlayer.setOnCompletionListener(mCompletionListener);
         mMediaPlayer.setOnBufferingUpdateListener(this);
         mMediaPlayer.setOnErrorListener(this);
         mMediaPlayer.setLooping(isLooping);
         mMediaPlayer.setDataSource(getContext(), mSource);
         mMediaPlayer.setSurface(surface);
         mMediaPlayer.prepare();
         mMediaPlayer.start();
     } catch (IllegalArgumentException e) {
         e.printStackTrace();
     } catch (SecurityException e) {
         e.printStackTrace();
     } catch (IllegalStateException e) {
         e.printStackTrace();
         mMediaPlayer.reset();
     } catch (IOException e) {
         e.printStackTrace();
     }
   }

   @Override
   public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}

  @Override
  public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
     surface.release();
     return true;
  }

  @Override
  public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
}

這對我有用:

videoView.setBackgroundColor(Color.WHITE); // Your color.
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        videoView.setBackgroundColor(Color.TRANSPARENT);
    }
});

至少兩年后,但我希望這會有所幫助。

以上都不適合我。 就我而言, onPrepared在黑框消失之前被調用,所以我仍然會看到黑框。

我需要一個解決方案,讓視頻在第一幀后不久出現。

所以我所做的是在 xml 中將 VideoView alpha 設置為 0:

android:alpha="0"

然后在開始播放視頻之前,我將 alpha 動畫恢復為 1:

videoView.animate().alpha(1);
videoView.seekTo(0);
videoView.start();

或者,您可以發布一個延遲的 Runnable 以將 alpha 設置為 1,而不是對其進行動畫處理。

這絕對是hacky,但比覆蓋圖像(IMO)更好。

boolean mRestored = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mRestored = savedInstanceState != null;
}

@Override
public void onPrepared(MediaPlayer mp) {

    if (!mRestored) vSurface.seekTo(1);
}

假設您將東西放入onSaveInstanceState savedInstanceState

只需顯示視頻中的一幀作為預覽。

vSurface.SeekTo(100);

我想只需使用 VideoView#setBackgroundDrawable()。

  1. 初始設置。

     VideoView.setBackgroundDrawable(yourdrawableid);
  2. 開始視頻

    VideoView.start(); VideoView.setBackgroundDrawable(0);

對於仍在為此尋找答案的人們,在onPrepared中連續調用VideoView.start()VideoView.pause()對我onPrepared 我知道這可能不是實現這一目標的理想方法,但它可能是代碼中所需解決方法最少的方法。 希望這對你也有用。

@Override
public void onPrepared(MediaPlayer mp) {
    mVideoView.start();
    mVideoView.pause();
}

這個對我有用:

在 XML 中:VideoView 隱藏在具有白色背景的相對布局后面

    <VideoView
      android:id="@+id/myVideo"
      android:layout_below="@+id/logo_top"
      android:layout_width="200dp"
      android:layout_height="200dp"
      android:layout_centerHorizontal="true" 
    />
    <RelativeLayout
      android:id="@+id/mask"
      android:background="#FFFFFF"
      android:layout_below="@+id/logo_top"
      android:layout_centerHorizontal="true"
      android:layout_width="200dp"  android:layout_height="200dp"
    >
    </RelativeLayout>

並在活動中:onCreate

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.acceuil);
    myVideo = (VideoView)  findViewById(R.id.myVideo);
    mask = (RelativeLayout)  findViewById(R.id.mask);
    String path = "android.resource://" 
      + getPackageName() + "/" + R.raw.anim_normal;
    myVideo.setVideoURI(Uri.parse(path));
    myVideo.start();
}

開始:

 public void onStart() { 
    final long time = System.currentTimeMillis();
    super.onStart();
    new CountDownTimer(5000, 100) { 
    @Override
        public void onTick(long l) {

            long time2 = System.currentTimeMillis();
            if((time2 - time) > 500) {
                mask.setVisibility(View.GONE);
            }
        }

}.start();

希望這可以幫助。

使用svVideoView.seekTo(position)

在 5 (ms) 內給出位置。

onPause():
position=svVideoView.getCurrentPosition()

onResume():
svVideoView.seekTo(position);

它對我的 Activity 和 Fragment 都有效。

VideoView mVideo = (VideoView) findViewById(R.id.yourViewViewId);
          mVideo.setVideoURI(mUri);
          mVideo.setZOrderOnTop(false);

SurfaceHolder surfaceholder = mVideo.getHolder();
surfaceholder.setFormat(PixelFormat.TRANSPARENT);

對我來說,設置setZOrderOnTop並沒有完全刪除播放 mp4 視頻時的初始黑框。 然而,它確實減少了黑框出現的時間。 我想完全刪除最初的黑框,所以我玩了一會兒,發現向前尋找 100 毫秒的視頻對我來說很有效。

請注意,我正在循環使用視頻,因此如果您不想循環播放視頻,只需刪除
mp.isLooping = true

以下是我用來解決問題的代碼段:

val path = "android.resource://" + packageName + "/" + R.raw.my_video
videoView.setVideoURI(Uri.parse(path))
videoView.setZOrderOnTop(true)
videoView.seekTo(100)
videoView.start()

videoView.setOnPreparedListener { mp ->
   videoView.setZOrderOnTop(false)
   mp.isLooping = true // Loops the video 
}

如果有人發現它有幫助,如果我能得到上述為什么有效的確切解釋,那仍然會很棒。

這個答案有點晚了,但也許其他用戶也有同樣的問題並找到了這個問題..

我已經通過最初設置 BackgroundResource 來處理它,然后在啟動視頻時,我將背景設置為不可見的顏色..

VideoView myView = findViewById(R.id.my_view);
myView.setBackgroundResource(R.drawable.some_resource);
// some stuff

// this is when starting the video
myView.setVideoUri(someUri);
// also set MediaController somewhere...
//...
// now set the backgroundcolor to be not visible (first val of Color.argb(..) is the alpha)
myView.setBackGroundColor(Color.argb(0, 0, 0, 0));
//...
myView.start();

這是一個很好的解決方案:

package com.example.videoviewpractice;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.MediaController;
import android.widget.VideoView;

public class MainActivity extends Activity {

    VideoView myVideoView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initVideo();
}

private void initVideo() {
    myVideoView = (VideoView) findViewById(R.id.videoView1);
    String url = "http://mtc.cdn.vine.co/r/videos/3DF00EB7001110633055418310656_1e50d6d9a65.3.2.mp4?" + 
            "versionId=KVMUFFGqe6rYRrGKgl8hxL6eakVAErPy";
    myVideoView.setVideoURI(Uri.parse(url));
    myVideoView.setMediaController(new MediaController(this));
    myVideoView.requestFocus();
}

public void gone(View v){
    myVideoView.setZOrderOnTop(true);
    View placeholder = (View) findViewById(R.id.placeholder);

    placeholder.setVisibility(View.GONE);
    myVideoView.start();
}

}

活動_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >

<FrameLayout
    android:id="@+id/frameLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_gravity="center"
    android:layout_marginTop="50dip" >

    <VideoView
        android:id="@+id/videoView1"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="top|center"
        android:visibility="visible" />

    <FrameLayout
        android:id="@+id/placeholder"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="top|center"
        android:background="@drawable/ic_launcher"
        android:onClick="gone" >
    </FrameLayout>

</FrameLayout>

</LinearLayout>

為了避免煩人的閃爍和黑屏問題,我編寫了FrameVideoView

它受益於“占位符解決方案”和(如果您的設備運行 API 級別 14 或更高級別)來自TextureView ,這比VideoView效率高得多。

我在我們的博客上寫了一篇文章來介紹它的實際作用。

使用起來很簡單:

FrameVideoView添加到布局:

<mateuszklimek.framevideoview.FrameVideoView
    android:id="@+id/frame_video_view"
    android:layout_width="@dimen/video_width"
    android:layout_height="@dimen/video_height"
  />

Activity找到它的實例並在onResumeonPause調用相應的方法:

public class SampleActivity extends Activity {

  private FrameVideoView videoView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple);

    String uriString = "android.resource://" + getPackageName() + "/" + R.raw.movie;
    videoView = (FrameVideoView) findViewById(R.id.frame_video_view);
    videoView.setup(Uri.parse(uriString), Color.GREEN);
  }

    @Override
    protected void onResume() {
      super.onResume();
      videoView.onResume();
    }

    @Override
    protected void onPause() {
      videoView.onPause();
      super.onPause();
    }
  }

我遇到過同樣的問題。 我發現其主要原因是使用FrameLayout作為父布局。 使用RelativeLayout作為VideoView的父布局

修改@emmgfx 的答案對我有用:

videoView.setBackgroundColor(Color.WHITE)
videoView.start()
Timer().schedule(100){
  videoView?.setBackgroundColor(Color.TRANSPARENT)
}

技巧是延遲視頻視圖直到視頻加載。 PS:這是科特林。

我找到了一個很好的解決這個問題的方法。 (在科特林)

在您的視頻視圖之上創建一個圖像視圖。 創建一個帶有處理程序的函數,並檢查是否 ( videoview.duration > 0 )

如果持續時間大於零,則將 imageview.visibility 設置為 INVISABLE,然后緊跟 handler.removeCallbacks(this)

調用 videoview.start 后調用上面的函數

代碼如下:

有趣的 showVideoView() {

    val handler = Handler()

    handler.postDelayed(object : Runnable {
        override fun run() {
            try {
                if (videoplayer_topthree.currentPosition > 0) {
                    videoview_topthreeloadingimage.visibility = View.INVISIBLE
                    videoview_topthreeprogressbar.visibility = View.VISIBLE
                    videoview_topthreefullname.visibility = View.VISIBLE
                    videoview_topthreeviews.visibility = View.VISIBLE
                    videoview_topthreedate.visibility = View.VISIBLE
                    videoview_topthreedescription.visibility = View.VISIBLE
                    videoview_topthreedimview.visibility = View.VISIBLE
                    handler.removeCallbacks(this)
                }
                handler.postDelayed(this, 250)
            } catch (e: Exception) {
                println("SHOW VIDEOVIEW CATCH WAS CAUGHT")
            }
        }

    }, 0)

}

這就是我調用這個函數的地方..

videoplayer_topthree.setOnPreparedListener {

        prepareSizing(it)
        initializeProgressBar()
        showVideoView()
        
    }

嘗試在大部分白色布局上播放大部分白色視頻會以非常明顯和煩人的方式顯示這些故障,尤其是在 Activity 轉換期間。 我設法完全擺脫故障的唯一方法是將來自該線程的一些不同答案和 elprl 在https://stackoverflow.com/a/9089245/3997253 上的答案混合在一起。

創建一個覆蓋 VideoView 的純色視圖

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

在創建中

...
coverView = findViewById(R.id.coverView)
videoView = findViewById(R.id.videoView)

videoView.setZOrderOnTop(false)
val surfaceHolder = videoView.holder
surfaceHolder.setFormat(PixelFormat.TRANSPARENT)

在啟動

...
videoView.setOnPreparedListener { mp ->
    // Fade out cover View to show VideoView once rendering has started
    mp.setOnInfoListener { _, what, _ ->
        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
            coverView.animate().alpha(0F)
            return@setOnInfoListener true
        }
        return@setOnInfoListener false
    }
    mp.isLooping = true
    videoView.start()
    videoView.requestFocus()
}

完成 VideoView 后

// Fade in cover View to hide the VideoView
coverView.animate().alpha(1F)

看到這個

VideoView videoView = (VideoView) findViewById(R.id.VideoView);
        MediaController mediaController = new MediaController(this);
        mediaController.setAnchorView(videoView);
        Uri video = Uri.parse("android.resource://your_package_name/"+R.raw.monkeysonthebed_video);

        videoView.setMediaController(mediaController);
        videoView.setVideoURI(video);
        videoView.start();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM