Android MediaPlayer setNextMediaPlayer 不工作

Posted

技术标签:

【中文标题】Android MediaPlayer setNextMediaPlayer 不工作【英文标题】:Android MediaPlayer setNextMediaPlayer not working 【发布时间】:2014-08-19 05:36:20 【问题描述】:

我的目标是创建一个VideoView 可以播放pre-defined 播放列表中的视频。

我正在尝试使用MediaPlayer.setNextMediaPlayer(...) 来实现两个视频之间的无缝过渡。但是,当第一个视频播放完毕后,第二个视频不会按照文档所述自动启动。

Xamarin Android 代码

    Queue<MediaPlayer> MediaPlayerList = null;
    private void PlayVideo()
    
        MediaPlayerList = new Queue<MediaPlayer>();

        //Let's go ahead and create all media players
        VideoView_CurrentVideoView = new VideoView(this);

        VideoView_CurrentVideoView.Completion += mVideoView_Completion;
        VideoView_CurrentVideoView.Prepared += mVideoView_Prepared;

        //Let's prepare all MediaPlayer
        for (int i = 0; i < VideoView_CurrentVideoChannel.VideoAssetList.Count; i++)
        
            string filePath = FilePath[i];
            if (i == 0)
            
                VideoView_CurrentVideoView.SetVideoPath(filePath);
                VideoContainer.AddView(VideoView_CurrentVideoView);
            
            else
            
                MediaPlayer mpNew = new MediaPlayer();
                mpNew.SetDataSource(filePath);
                MediaPlayerList.Enqueue(mpNew);
            
        

        VideoView_CurrentVideoView.Start();
    

    void mVideoView_Completion(object sender, EventArgs e)
    
        MediaPlayer mp = (MediaPlayer)sender;
        mp.Release();
    

    void mVideoView_Prepared(object sender, EventArgs e)
    
        MediaPlayer mp = (MediaPlayer)sender;

        //Take the next available MediaPlayer from the queue
        MediaPlayer nextMediaPlayer = MediaPlayerList.Dequeue();

        //Put the current MediaPlayer at the end of the queue
        MediaPlayerList.Enqueue(mp);


        nextMediaPlayer.Prepare();
        mp.SetNextMediaPlayer(nextMediaPlayer);
    

任何帮助或建议将不胜感激。这是在Xamarin android 中编码的。

更新 #1:将 .Prepare() 远离 Prepared() 事件后

    Queue<string> VideoListQueue = null;
    MediaPlayer NextMediaPlayer = null;
    private void PlayVideo()
    
        string filePath = FilePath[0];


        //Create video view
        if (VideoContainer.ChildCount == 0)
        
            //setup the videoview container
            VideoView_CurrentVideoView = new VideoView(this);
            VideoView_CurrentVideoView.Info += VideoView_CurrentVideoView_Info;
            VideoView_CurrentVideoView.Error += VideoView_CurrentVideoView_Error;

            LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
            param.LeftMargin = 0;
            param.RightMargin = 0;
            param.BottomMargin = 0;
            param.TopMargin = 0;

            VideoView_CurrentVideoView.LayoutParameters = param;
            VideoView_CurrentVideoView.LayoutParameters.Width = ViewGroup.LayoutParams.FillParent;
            VideoView_CurrentVideoView.LayoutParameters.Height = ViewGroup.LayoutParams.FillParent;

            VideoView_CurrentVideoView.Completion += VideoView_CurrentVideoView_Completion;
            VideoView_CurrentVideoView.Prepared += VideoView_CurrentVideoView_Prepared;
            VideoContainer.AddView(VideoView_CurrentVideoView);
        

        VideoView_CurrentVideoView.SetVideoPath(filePath);
        VideoView_CurrentVideoView.SeekTo(0);
        VideoView_CurrentVideoView.Start();
    

    void VideoView_CurrentVideoView_Prepared(object sender, EventArgs e)
    
        //Do nothing at this moment
        MediaPlayer mp = (MediaPlayer)sender;
    

    void VideoView_CurrentVideoView_Completion(object sender, EventArgs e)
    
        //GC the finished MediaPlayer
        MediaPlayer mp = (MediaPlayer)sender;
        mp.Reset();
        mp.Release();
        mp = null;


        //Preparing the next MediaPlayer
        MediaPlayer currentPlayer = NextMediaPlayer;
        NextMediaPlayer = SetupNextMediaPlayer();
        currentPlayer.SetNextMediaPlayer(NextMediaPlayer);
    


    MediaPlayer SetupNextMediaPlayer()
    
        MediaPlayer mp = new MediaPlayer();
        //When the video start playing, let's get ready for next one
        string sourceURL = VideoListQueue.Dequeue();
        VideoListQueue.Enqueue(sourceURL);

        string filePath = sourceURL;


        mp = new MediaPlayer();
        mp.Info += VideoView_CurrentVideoView_Info;
        mp.Completion += VideoView_CurrentVideoView_Completion;
        mp.Prepared += VideoView_CurrentVideoView_Prepared;

        mp.SetDataSource(filePath);
        mp.Prepare();


        //Fire back the created MediaPlayer object to the caller
        return mp;
    

    void VideoView_CurrentVideoView_Info(object sender, MediaPlayer.InfoEventArgs e)
    
        Console.WriteLine("What = " + e.What);

        switch (e.What)
        
            case MediaInfo.VideoRenderingStart:
                
                    //This is only happening on video first started
                    NextMediaPlayer = SetupNextMediaPlayer();
                    e.Mp.SetNextMediaPlayer(NextMediaPlayer);
                    break;
                
        

    

    void VideoView_CurrentVideoView_Error(object sender, MediaPlayer.ErrorEventArgs e)
    
        e.Handled = true;
    

此时,媒体播放器将在第一个视频播放完毕后开始播放第二个视频。但是,第二个视频只有声音,没有视频显示。

谁知道我做错了什么?我有一种感觉,它必须与未附加到 SurfaceView 的 MediaPlayer 做一些事情。但是,我使用 VideoView 创建了视图,如何从 VideoView 获取 Surface?

【问题讨论】:

你好 WorldWind,你有没有机会找到解决这个问题的方法?我也有同样的问题,第二个视频只播放声音(没有视频)。谢谢。 【参考方案1】:

关于仅用声音播放第二个视频:尝试使用以下方法为每个 MediaPlayer 实现 OnCompletionListener 侦听器:

mediaPlayer.setOnCompletionListener(new OnCompletionListener() 

    @Override
    public void onCompletion(MediaPlayer mp) 
        mp.setDisplay(null); //for current mediaPlayer
        nextMediaPlayer.setDisplay(getHolder()); //for next video
    
);

我不能说它是无间隙的,但它以某种方式起作用。为了存档,我不使用标准的 VideoView,而是使用从 SurfaceView 扩展而来的自定义 View。

【讨论】:

这样做的问题是,这会在视频中造成明显的停顿。 @Flyview 是的。如果不可接受,解决方案可以是在本地使用 FFmpeg 连接视频或在后端实现此类功能。不过,它们都不简单。 是的,我希望我能找到一个简单的解决方案。我尝试使用 setNextMediaPlayer 的全部原因是因为我想无缝地循环播放相同的视频而没有明显的差距。我认为 AwesomePlayer 过去可以完美循环播放,但使用 Nuplayer 重新启动视频时会出现间隙。【参考方案2】:

如果您在 .Completion 事件中准备并播放下一个媒体播放器会怎样?你试过吗?虽然可能会有一点延迟

【讨论】:

感谢您的回复。目的是使其无缝。不过,这是一个很好的建议,我会先对其进行测试,以确保 SetNextMediaPlayer(...) 按预期工作。 这种方式也很有可能是无缝的。可能不在旧的和低规格的设备中 经过一系列测试,结果如下。它是功能性的,但只有音频。第一个视频同时播放了视频+音频,当视频 1 完成后,视频 2 开始播放,但只有音频。我错过了什么琐碎的事情吗? 已添加,请参阅原始帖子中的更新 #1。谢谢 如果您在 PlayVideo() 之外定义 VideoVew_CurrentVideoView 并在完成时执行以下操作:VideoView_CurrentVideoView.SetVideoPath(NextfilePath); VideoView_CurrentVideoView.SeekTo(0); VideoView_CurrentVideoView.Start();【参考方案3】:

经过多年的测试,并非所有硬件都会出现此问题。例如,我在 Nexus7 上运行相同的 APK,它看起来是无缝的,并且一切正常。相反,如果我在 Amlogic 媒体播放板上运行它,就会出现上述问题。

我决定结束这篇文章,得出的结论是它与硬件有关。我知道有人通过在 OpenGL 中运行所有东西来克服这个限制,但这完全是一个单独的野兽来处理。

结论

如果您遇到与上述类似的问题,那么您无能为力,因为它严重依赖于硬件。

【讨论】:

以上是关于Android MediaPlayer setNextMediaPlayer 不工作的主要内容,如果未能解决你的问题,请参考以下文章

Android:MediaPlayer.setDataSource(FileDescriptor fd) vs MediaPlayer.setDataSource(FileDescriptor fd,

android的MediaPlayer.create方法怎么用

Android开发---MediaPlayer简单音乐播放器

Android MediaPlayer错误码整理

Android:MediaPlayer 未发布就完成了

Android -- MediaPlayer内部实现简析