流媒体音频播放器缓冲时间问题

10

我正在使用MediaPlayer通过HTTP流式传输收听广播。在Lollipop上,我的流需要大约一分钟才能开始,这是不可接受的。在Kitkat上大约需要20秒,这已经很痛苦了,现在变得无法使用。

这个组件与缓冲相关存在一个众所周知的问题:缓冲的字节数是硬编码的,不能更改。

我的代码非常标准

player.reset();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(streamUrl);
player.prepareAsync();

而在准备好的情况下,我会去做。

player.start();

我听说过一些替代方案,如GStreamer,但我不能在Windows上使它工作。

我想知道是否有人有一个可行的解决方案来通过HTTP流传播广播,并且延迟开始较小。

编辑

我测试了ExoPlayer,但我得到的最低启动时间为15秒。播放器停留在“准备”状态(不是缓冲,到目前为止我看到的情况)。

编辑

流的格式是AAC

编辑

我测试了https://code.google.com/p/aacdecoder-android/,但这个库唯一的问题是不支持在线流暂停。我的应用程序需要支持在线流暂停。


你的流媒体使用什么比特率?例如 32 kbps、64 kbps 等。 - Simas
@Simas:它使用32 kbps。我知道使用更大的比特率会改善这个问题,但似乎不是一个真正的解决方案。 - StackOverflower
你正在播放什么格式的音频,AAC吗? - Bojan Kseneman
@BojanKseneman:是的,AAC。 - StackOverflower
一个 Web API 是一个选项吗? - IndieTech Solutions
@Alundra the dreamwalker:除非客户端有合适的选项,否则不是最后的选择。让我们说那是最后的选择。 - StackOverflower
7个回答

10
如果您的使用情况与GPL/LGPL许可证兼容,则VLC应该正是您所需的。VLC能够在3G网络上从您的URL进行流媒体传输,仅有约1秒的延迟。
步骤1: 下载VLC源代码并按照说明进行编译。
步骤2: 最重要的类是org.videolan.vlc.audio.AudioServiceController,它被从org.videolan.vlc.gui.MRLPanelFragement.processUri() --> org.videolan.vlc.util.Util.openStream(Context, String) --> AudioServiceController.load(String, boolean)中调用。您可以除去除了AudioServiceController及其支持类之外的所有不必要的代码以减小大小。

我从未听说过这个,我将测试这个解决方案。谢谢。 - StackOverflower
@Kai:你知道是否有使用Android Studio的可行示例吗?我不确定在赏金迫使我选择获胜者之前是否有时间测试这个解决方案。正如shri所说,必须有支持暂停的解决方案。 - StackOverflower
凯,你说得对。虽然要求是从上次离开的地方继续播放,但这有点疯狂,我可能能说服他们放弃这个想法。当你刚开始播放时,服务器会在流媒体之前发送广告。只需要避免在每次播放时发送这个广告就足够了。如果我使用停止功能,当点击播放时广告将会被发送,这就是暂停要求背后的主要原因:避免广告的出现。 - StackOverflower
如果能看到一个可行的示例就太好了,因为我今天没有太多时间来测试它。如果这个方法有效,我想授予您赏金,但我不确定我是否能及时完成。真希望您早些发布这个! - StackOverflower
我会为您打包我正在使用的版本供您下载,但它只能在Linux上运行,并且可能需要安装所有必要的工具才能正常运行。 - Kai
显示剩余9条评论

3

我建议从MediaPlayer切换到ExoPlayer。使用ExoPlayer,可以按照以下方式设置缓冲参数:

public static ExoPlayer newInstance(int rendererCount, int minBufferMs, int minRebufferMs) {
  return new ExoPlayerImpl(rendererCount, minBufferMs, minRebufferMs);
}

minBufferMS 意味着必须缓冲的最小数据持续时间,以便在用户执行操作(例如搜索)后开始或恢复播放。

minRebufferMs 意味着必须缓冲的最小数据持续时间,以便在播放器调用重新缓冲之后恢复播放(即由于缓冲区耗尽而不是由于用户操作(例如开始播放或搜索)而发生重新缓冲)。

默认值分别为500和5000。


这是一个ExoPlayer的演示应用程序,您可以轻松测试缓冲状态。https://github.com/google/ExoPlayer/tree/master/demo - Dekra
我测试了ExoPlayer,但我得到的最低启动时间是15秒。播放器卡在“准备”状态(不是缓冲,那是后来才出现的)。我想这就是为什么几个月前我测试时没有继续使用这个播放器的原因:当时与我所拥有的相比并没有任何改进。 - StackOverflower
你能分享一下你正在测试的链接吗? - Dekra
1
看起来你的示例代码是针对 Exoplayer 1 的。我在 Exoplayer 2 中找不到 ExoPlayerImpl - Behrouz.M
1
使用ExoPlayer 2(r2.1.3)在Android 6.0.1上,测试来自https://radio.abc.net.au/help/streams的mp3,96kbps流时,我看到最小延迟(<2秒),而使用相同流的mediaPlayer则会出现约15-30秒的延迟。 - Maks
显示剩余3条评论

1

你应该避免使用媒体播放器来播放实时广播流。只是出于好奇,为什么?有关此事的文档/文章/其他资料吗? - aga
我们注意到许多设备上的媒体播放器存在问题。虽然这些问题可能与编解码器有关,但使用上述库似乎可以在这些设备上正常工作。 - Bojan Kseneman
Bojan,有没有一种方法可以配置ACC解码器中的输入缓冲区大小? - shri
当然。有两种方法: aacPlayer.setAudioBufferCapacityMs(343); aacPlayer.setDecodeBufferCapacityMs(3242); 请注意,我只输入了一些愚蠢的值。 - Bojan Kseneman
谢谢你的回答。我几个月前测试过这个库,它非常完美,除了一个问题:它不允许暂停流,只允许停止。不幸的是,这对我的应用程序有所影响。 - StackOverflower
是的,那是真的,我们先前使用stop来暂停,playAsync来恢复。 - Bojan Kseneman

0

流媒体延迟有两种,一是缓冲延迟(启动时的延迟),二是广播延迟。

在媒体播放器中,流需要1分钟来缓冲。因此,我们首先需要看一下如何减少填充缓冲区所需的时间。我不确定在Android媒体播放器代码中是否可以配置缓冲区大小。

但是,如果我们尝试使用AAC解码器库(https://code.google.com/p/aacdecoder-android/downloads/detail?name=aacdecoder-android-0.8.zip),那么我们就有了填充输入缓冲区的功能。

请参考下面的代码片段,您可以根据需要填充输入缓冲区容量,然后开始播放。由于我们可以控制输入缓冲区的容量,因此我们可以尝试减少启动播放的时间延迟。请检查这是否可以帮助您。

 /**
 * Sets the audio buffer (AudioTrack) capacity.
 * The capacity can be expressed in time of audio playing of such buffer.
 * For example 1 second buffer capacity is 88100 samples for 44kHz stereo.
 * By setting this the audio will start playing after the audio buffer 
   is    first filled.
 *
 * NOTE: this should be set BEFORE any of the play methods are called.
 *
 * @param audioBufferCapacityMs the capacity of the buffer in milliseconds
 */
  public void setAudioBufferCapacityMs( int audioBufferCapacityMs ) {
    this.audioBufferCapacityMs = audioBufferCapacityMs;
  }

谢谢你的回答。我几个月前测试了这个库,它非常完美,除了一个问题:它不允许暂停流,只允许停止。不幸的是,这对我的应用程序有影响。 - StackOverflower
好的,我的理解是在实时流传输中,我们通常不会暂停。当我们从录制的内容进行回放时,需要暂停内容。 - shri
我有点同意,但我的要求不同。我需要允许在直播流上暂停。谢谢! - StackOverflower

0

我会发布我是如何做到的以及它带来了什么不同。这不是实时音频项目(它是来自在线API的MP3,但大约为4-6MB),因此可能会有所不同,但在我的Genimotion VM上加载时间少于3-5秒。

我知道这几乎与您的代码相同。也许如果您能分享URL或类似的URL出现相同的问题,我可以在我的应用程序中进行测试。

runThread(url);//ran on the oncreate.


 private void runThread(final String url) {
    new Thread() {
        public void run() {
            mediaPlayer  = new MediaPlayer();//mediaplayer is a global variable.
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

                try{
                    mediaPlayer.setDataSource(url);

                    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mediaPlayer) {
                            //audio did finish.

                        }
                    });
                    mediaPlayer.prepare(); // might take long! (for buffering, etc)
                    duration = mediaPlayer.getDuration();
                    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {

                                    //here you should start playing it.
                                }
                            });
                        }
                    });
                }
                catch(Exception e)
                {

                }


            }
    }.start();
}

在搭载果冻豆系统的 Nexus 4 上进行测试,响应时间相似。


0
这仅适用于mp3媒体播放器,我们可以使用此代码。
 mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
            public void onBufferingUpdate(MediaPlayer mp, int percent)
            {
                double ratio = percent / 100.0;
                int bufferingLevel = (int)(mp.getDuration() * ratio);
                seekBar.setSecondaryProgress(bufferingLevel);
            }
        });

0

如果你愿意在库上花一些钱,我推荐 Bass 它有全套的 API 调用,可以整合,而且有很好的文档。你可以测试试用共享版。

如果你不想花钱。我强烈推荐 VLC,就像 @Kai 提到的那样,未来你也可以扩展应用程序以进行视频流。我之前使用过 API 来为我的水族馆进行直播。 @Kai 已经提供了必要的链接。

查看此 链接 以获取更多信息。


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