Android的MediaPlayer在暂停状态下设置Surface

6

编辑:

显然这与多个活动无关,而与视频文件的编码有关。

我将尝试简化问题:我有一个处于暂停状态的MediaPlayer对象,当我调用mediaPlayer.getCurrentPosition()时,我得到的结果是准确的。当我在此对象上调用mediaPlayer.setSurface()(使用不同的表面)后跟mediaPlayer.play()时,视频播放的位置与getCurrentPosition()返回的位置不同。我在API >= ICE_CREAM_SANDWICH上进行测试。

  • 测试了在项目中使用本地资源和通过网络流,结果:没有区别。

视频文件链接:http://wpc.4ba9.edgecastcdn.net/804BA9/testenvmedia/m_8705_LuS3w7ctSZjB.mov.bs.mp4


我有两个活动,Activity-A和Activity-B。

Activity-A使用MediaPlayer从远程流向TextureView播放视频, 它还拥有一个按钮,其目的是:

  1. 调用mediaPlayer.pause();

  2. 打开Activity-B。

Activity-B还拥有一个TextureView,它应该使用相同的MediaPlayer对象在其当前位置播放相同的视频。

Activity-A onCreate方法:

    textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {        
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int w, int h) {
            try {
                final MediaPlayer mediaPlayer = MyApplication.getMediaPlayer();
                mediaPlayer.setDataSource(context, videoURI);
                mediaPlayer.setSurface(new Surface(surfaceTexture));
                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mediaPlayer.setLooping(shouldLoop);
                mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        mp.start();
                    }
                });

                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

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

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; }

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

    btnFullScreen.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {     
        Log.e("WHATEVER", ">>> pause video at " + MyApplication.getMediaPlayer().getCurrentPosition());
        MyApplication.getMediaPlayer().pause();
        Intent intent = new Intent(getActivity(), ActivityB.class);
        startActivity(intent);
    }});

Activity-B的onCreate方法:

        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int w, int h) {
            MediaPlayer mediaPlayer = MyApplication.getMediaPlayer();
            mediaPlayer.setSurface(new Surface(surface));

            Log.e("WHATEVER", ">>> resume video at " + mediaPlayer.getCurrentPosition());
            mediaPlayer.start();
        }

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

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }

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

日志输出:

10-10 17:33:15.966  13886-13886/com.whatever.android.debug E/WHATEVER﹕ >>> pause video at 1958
10-10 17:33:16.817  13886-13886/com.whatever.android.debug E/WHATEVER﹕ >>> resume video at 1958

尽管看起来MediaPlayer将从那个确切的位置恢复,但对于不同的视频,我在Activity-B中每次尝试播放大多数视频时都会得到不同的行为,其中大多数视频每次都从完全相同的帧开始,另一个视频则每次从某个其他点开始。

根据Android的MediaPlayer.SetSurface()方法文档:

此方法可以在任何状态下调用,调用它不会改变对象状态。

非常感谢您的帮助。 谢谢!


你尝试过在单例中初始化和创建MediaPlayer吗?http://www.vogella.com/articles/DesignPatternSingleton/article.html - A.S.
1
@TomReznik 你遇到的特定媒体文件是否在网上某个地方可用?它们是什么类型的文件,你最后提到的文件离所需位置有多远?有些文件不支持随机寻找,而其他一些可能具有稀疏的 i 帧,导致播放恢复到稍微不同的位置。 - Dave
@Dave在另一台设备上进行了测试(最初是LG Nexus 4,现在是HTC Sensation),在HTC上,视频从开头播放。 - woot
1
我快速查看了你的视频。VLC播放器可以随意跳转到任何时间,但Totem和ffplay拒绝在视频的第9秒以外的任何地方跳转。我还看到过一篇关于ffmpeg无法正确剪切使用Lavf54.0.100编码的视频的帖子(该视频具有该编码)。我的最佳猜测与你的相同,我认为Android的AwesomePlayer在处理某些编码时与大多数其他播放器具有相同或类似的寻找限制。除非编写OMX编解码器,否则我认为你应该只需找到另一个用于测试的视频即可。 - Dave
@Dave 感谢您的建议!我们有自己的编码服务器来完成这项工作。我会在阅读了您的评论后检查编码设置,并在获取更多信息后发布更新。 - woot
显示剩余10条评论
2个回答

8

看起来您的问题是针对特定视频的,更多关键帧将有助于播放器更准确地恢复播放。

尝试重新使用ffmpeg和libx264进行重新编码,尝试添加以下参数:

-g=25 -keyint_min=25

0
尝试使用Intent.putExtra()将您的MediaPlayer的位置从Activity A传递到Activity B。因此,在Activity A中调用意图启动Activity B时,您应该这样做:
 public void onClick(View v) {     
    Log.e("WHATEVER", ">>> pause video at " + MyApplication.getMediaPlayer().getCurrentPosition());
    MyApplication.getMediaPlayer().pause();
    int position = MyApplication.getMediaPlayer().getCurrentPosition(); //new line added
    Intent intent = new Intent(getActivity(), ActivityB.class);
    intent.putExtra("position", position); //another new line of code
    startActivity(intent);
}

现在在 Activity B 中,寻找调用 start 之前媒体播放器暂停的位置,像这样:

@Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int w, int h) {
        MediaPlayer mediaPlayer = MyApplication.getMediaPlayer();
        mediaPlayer.setSurface(new Surface(surface));

        Log.e("WHATEVER", ">>> resume video at " + mediaPlayer.getCurrentPosition());
        mediaPlayer.seekTo(getIntent().getExtras().getInt("position"));// new line of code
        mediaPlayer.start();
    }

我也尝试过了,它不起作用,无论如何 mediaPlayer.seekTo() 在我指定的情况下几乎没有任何作用。 - woot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接