2010-10-06 100 views
25

我可以通過執行OnCompletionListener來精確地播放視頻,以將數據源設置爲不同的文件。那裏沒有問題。我打電話reset()prepare()就好。Android:MediaPlayer無縫或無縫視頻播放

我無法弄清楚的是如何擺脫數據源更改和新視頻啓動之間的1-2秒間隔屏幕閃爍。差距顯示黑屏,我還沒有找到任何方法來解決它。

我試着將父視圖的背景設置爲圖像,但它設法繞過。即使SurfaceView是透明的(這是默認情況下)。我也嘗試同時播放多個視頻文件,並在一個結束時切換mediaplayer的顯示,另一個應該開始。

我試過的最後一件事是在視頻「準備」時臨時顯示的背景中顯示第二個視圖,並在視頻準備開始時將其刪除。這也不是非常無縫。

有沒有什麼辦法擺脫這種差距。在一個循環中運行一個視頻奇妙地工作,並且正是我想要的,除了它正在通過相同視頻觀看,而不是播放我選擇的其他視頻。

public class Player extends Activity implements 
     OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback { 
     private MediaPlayer player; 
    private SurfaceView surface; 
    private SurfaceHolder holder; 

    public void onCreate(Bundle b) { 
     super.onCreate(b); 
     setContentView(R.layout.main); 
     surface = (SurfaceView)findViewById(R.id.surface); 
     holder = surface.getHolder(); 
     holder.addCallback(this); 
     holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
    } 

    public void onCompletion(MediaPlayer arg0) { 
     File clip = new File(Environment.getExternalStorageDirectory(),"file2.mp4"); 
     playVideo(clip.getAbsolutePath()); 
    } 
    public void onPrepared(MediaPlayer mediaplayer) { 
     holder.setFixedSize(player.getVideoWidth(), player.getVideoHeight()); 
     player.start(); 
    } 

    private void playVideo(String url) { 
     try { 
      File clip = new File(Environment.getExternalStorageDirectory(),"file1.mp4"); 

      if (player == null) { 
       player = new MediaPlayer(); 
       player.setScreenOnWhilePlaying(true); 
      } 
      else { 
       player.stop(); 
       player.reset(); 
      } 
      player.setDataSource(url); 
      player.setDisplay(holder); 
      player.setOnPreparedListener(this); 
      player.prepare(); 
      player.setOnCompletionListener(this); 
     } 
     catch (Throwable t) { 
      Log.e("ERROR", "Exception Error", t); 
     } 
    } 
+0

雖然這已經發布了一段時間後,我面臨同樣的問題。即使使用videoview,在切換視頻時我仍然存在差距。有沒有其他方法可以解決這個問題? – dulys 2011-10-21 12:37:26

回答

2

main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:background="@drawable/background" 
    android:layout_height="fill_parent"> 
    <SurfaceView 
     android:id="@+id/surface" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_gravity="center"> 
    </SurfaceView> 
</FrameLayout> 

Player.java太多的時間浪費試圖找出如何發揮連續視頻沒有 「差距」,我傾向於不可能。除非你能夠深入到原生水平並實現自己的播放器,否則Android的媒體播放器根本不支持無縫播放。

+0

我通過黑客實現了這一點。我在一個服務中的兩個mediaplayer實例之間切換。我有一個可配置的int變量,以便在媒體資產A結束之前開始播放媒體資產B「N」秒。 – Krafty 2014-04-25 00:00:15

+0

這很酷,但根據經驗我可以告訴你,即使在同一個設備上測試,確切的時間幾乎是不可能設置的,因爲設備有時可能在內存上運行不足,導致轉換不精確。 – josephus 2014-04-25 01:14:09

+0

@ user721448無論如何,我建議你在這裏發佈你的代碼作爲答案,讓我們測試一下。我已經與其他項目一起前進,沒有找到解決這個問題的工作方案,但我仍然對解決方案感到好奇。 – josephus 2014-04-25 01:20:04

1

我還沒有在MediaPlayer上進行視頻播放,但是當流由於用戶從3G切換到Wifi而被中斷時,我做了類似於音頻文件的操作。

我認爲你看到的延遲是媒體播放器緩衝輸入文件的時候。 所以也許你可以在開始時定義兩個球員?你應該定義數據源並準備兩個玩家,但只能啓動其中一個。

然後在您的onCompletionListener中,您可以翻轉它們而不是重置現有設置並設置新的數據源。

player.release(); 
    player = flipPlayer; 
    flipPlayer = null; 
    player.start(); 

顯然,你需要或者使用不同的onPreparedListener爲flipPlayer或採取player.start()從onPrepare的。 (既然你是同步調用它,我不會認爲這是一個問題)。

+0

hm。值得一試。雖然不會釋放()實際上在那裏留下一個空白屏幕? – josephus 2012-02-28 10:52:06

0

你嘗試有現成的(開/準備好了)2 VideoView,其中一個可見,其他不可見並停止,並且很快你會得到OnCompletionListener回調,使第二個可見,啓動它並隱藏第一個。 與此同時,作爲第二個播放,您可以打開/準備在第一VideoView打開/準備另一個文件。

+0

onCompletionListener將在第一個視頻完成播放後立即調用。 Gap將從那裏開始,並在開始播放第二個之後結束(當然,在改變可見性之後)。將無法工作。 – josephus 2012-02-28 10:49:43

4

我也有同樣的問題,下面的鏈接

VideoView Disappears for a second when video is changed

所概述的,但如果你試圖使用Android 4.0以上版本(ICS)不會出現此問題。我開始將VideoView.java和MediaPlayer.java從4.0移植到我的應用程序,但這似乎很複雜,直到現在還沒有運氣。基本上它似乎是舊版本的本機代碼中的一個錯誤。

0

@ user1263019 - 您是否可以將Android 4.0 MediaPlayer移植到您的應用程序?我面臨同樣的問題,我正在尋找一個很好的解決方案。我的情況是在SurfaceView上有一個圖像,爲了顯示視頻播放,它應該被隱藏,但是在調用start()和視頻的實際開始之間存在差距。目前唯一的解決方案是啓動一個Thread來檢查getCurrentPosition()是否大於0.

關於主題 - 我認爲不可能有無縫播放,儘管Winamp聲稱擁有這樣的能力。骯髒的黑客是在第一個播放器播放結束前幾秒準備第二個播放器,然後在播放結束之前調用第二個播放器的100-200ms的start()。

0

在你exoplayer實現(或媒體播放器)使用一個處理器反覆發佈可運行,一邊玩,獲取當前的跟蹤時間,並把它傳遞給回調:

public interface MediaAction { 
    public void onTrackingChanged(long currentPosition); 
} 

public class ExoPlayerImplementation implements Exoplayer { 

    .. 

    private MediaAction mediaActionCallback; 
    public void setMediaActionCallback(MediaAction ma) { 
    mediaActionCallback = ma; 
    } 
    public void releaseMediaAction() { mediaActionCallback = null; } 

    private Handler trackingCallback = new Handler(Looper.getMainLooper()); 

    Runnable trackingTask; 
    private Runnable getTrackingTask() { 
    Runnable r = new Runnable { 
     @Override public void run() { 
     long currentPosition = getCurrentPosition(); 
     if (mediaActionCallback != null) { 
      mediaActionCallback.onTrackingChanged(currentPosition); 
     } 
     // 60hz is 16 ms frame delay... 
     trackingCallback.postDelayed(getTrackingTask(), 15); 
     } 
    }; 
    trackingTask = r; 
    return r; 
    } 

    public void play() { 
    // exoplayer start code 
    trackingCallback.post(getTrackingTask()); 
    } 

    public void pause/stop() { 
    trackingCallback.removeCallbacks(trackingTask); 
    } 

    .. 

} 

現在你可以跟蹤當前位置實際上已經改變 - 如果它已經改變,那麼你可以顯示你的視頻輸出視圖/交換視圖/刪除預覽(即,使用MediaExtractor獲取初始幀,覆蓋作爲預覽在ImageView中,然後隱藏一旦當前位置增加)。您可以通過將代碼與狀態監聽器相結合來使代碼更加完整:然後您知道是否正在緩衝(檢查緩衝位置與當前位置),實際播放,暫停還是使用適當的回調(在MediaAction中)停止。您可以將此方法應用於MediaPlayer和ExoPlayer類(因爲它只是一個接口和處理程序)。

希望有幫助!