Android:MediaPlayer无缝或无缝视频播放

时间:2010-10-06 21:41:48

标签: android video media-player

我可以通过实现 OnCompletionListener 将数据源设置为不同的文件来连续播放视频。没有问题。我打电话给 reset() prepare()就好了。

我无法弄清楚的是,如何摆脱数据源更改和新视频启动之间的1-2秒间隙屏幕闪烁。差距显示为黑屏,我没有找到任何解决方法。

我尝试将父视图的背景设置为图像,但它设法绕过它。即使 SurfaceView 是透明的(默认情况下也是如此)。我也尝试同时播放多个视频文件,并在一个结束而另一个结束时切换媒体播放器的显示开始。

我尝试过的最后一件事就是在视频“准备”时暂时显示背景中的第二个视图,并在视频准备好开始时将其删除。这也不是很无缝。

有没有办法摆脱这种差距。在循环中运行视频效果非常好,完全符合我的要求,除了它正在查看同一个视频而不是播放我选择的另一个视频。

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

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

7 个答案:

答案 0 :(得分:4)

我也遇到与下面链接

中列出的问题相同的问题

VideoView Disappears for a second when video is changed

但是如果你尝试使用Android 4.0+(ICS),这个问题就不会发生。我开始将VideoView.java和MediaPlayer.java从4.0移植到我的应用程序,但那似乎很复杂,直到现在都没有运气。基本上它似乎是旧版本的本机代码中的一个错误。

答案 1 :(得分:2)

经过太多浪费时间试图弄清楚如何连续播放没有“差距”的视频,我倾向于不可能。除非您能够深入挖掘本地级别并实施自己的播放器,否则Android的媒体播放器目前不支持无缝播放。

答案 2 :(得分:1)

我没有在MediaPlayer上进行视频播放,但是当流因用户从3G切换到Wifi而中断时,我已经完成了与音频文件类似的操作。

我认为你看到的延迟是在媒体播放器缓冲输入文件的时候。 那么也许你可以在一开始就定义两个玩家?您应该定义数据源并准备两个玩家但只启动其中一个。

然后在你的onCompletionListener中,你可以翻转它们,而不是重置现有的并设置一个新的数据源。

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

显然你需要为flipPlayer使用不同的onPreparedListener,或者从onPrepare中取出player.start()。 (因为你同步调用它我不会认为这是一个问题)。

答案 3 :(得分:1)

我不认为这是可能的。

原因:Mortplayer也适用于Windows mobile,其优势之一是它支持无间隙播放。然而,它不在Android版本的应用程序中,并且开发人员自己写道SDK不允许它在xda上: http://forum.xda-developers.com/showpost.php?p=5364530&postcount=5

HTH,Daniele

答案 4 :(得分:0)

你有没有准备好(打开/准备好)2个VideoView,其中一个是可见的,另一个是不可见的并停止了,很快就会得到OnCompletionListener回调,让第二个可见,启动它,然后隐藏第一个。 同时,当第二个播放时,您可以在第一个VideoView上调用open / prepare来打开/准备另一个文件。

答案 5 :(得分:0)

@ user1263019 - 你能将Android 4.0 MediaPlayer移植到你的应用程序吗?我面临同样的问题,我正在寻找一个很好的解决方案。我的情况是在SurfaceView上有一个图像应隐藏以显示视频播放,但调用start()和视频的实际开始之间存在差距。到目前为止唯一的解决方案是启动一个Thread来检查getCurrentPosition()是否是&gt; 0

关于这个主题 - 我认为不可能有无间隙播放,尽管Winamp声称拥有这样的能力。肮脏的黑客是在第一个播放器播放结束前几秒准备第二个播放器,然后在播放结束前100-200ms调用第二个播放器的start()。

答案 6 :(得分:0)

在你的exoplayer实现(或媒体播放器)中,使用处理程序重复发布runnable,同时播放,获取当前跟踪时间并将其传递给回调:

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

希望有所帮助!