2010-10-06 96 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类(因为它只是一个接口和处理程序)。

希望有帮助!