为什么Exoplayer在带宽变化时不会切换HLS轨道

时间:2018-01-30 18:05:04

标签: exoplayer exoplayer2.x

我有这个简单的.m3u8文件

#EXTM3U
#EXT-X-VERSION:5

#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English stereo",LANGUAGE="en"

#EXT-X-STREAM-INF:BANDWIDTH=1728000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_360_800000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=628000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=320x180,AUDIO="audio"
https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_180_250000.m3u8

使用simpleExoplayer我加载此流:

// 1. Create a default TrackSelector
Handler mainHandler = new Handler();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
    new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
    new DefaultTrackSelector(videoTrackSelectionFactory);

// 2. Create the player
SimpleExoPlayer player =
    ExoPlayerFactory.newSimpleInstance(context, trackSelector);

// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
    Util.getUserAgent(context, "yourApplicationName"), bandwidthMeter);
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new HlsMediaSource.Factory(dataSourceFactory)
    .createMediaSource(mp4VideoUri);
// Prepare the player with the source.
player.prepare(videoSource);
player.setPlayWhenReady(true);

但即使在高WIFI互联网上,它也总是选择具有320x180分辨率的第二首曲目,并且永远不会切换到具有640x360分辨率的更高音轨。

如果我用maxInt替换DEFAULT_MAX_INITIAL_BITRATE那么它会正确选择1rt轨道(640x360)但是如果在播放过程中我切断了wifi以让移动设备只使用低3G连接,那么它将永远不会切换到第二首曲目(320x180),每次播放都会卡住

同时检查MediaCodecUtil.getDecoderInfo("video/avc", false).adaptive并返回TRUE

我做错了什么? hls在simpleExoPlayer中是否正常工作?

2 个答案:

答案 0 :(得分:6)

DefaultBandwidthMeter是计量网络容量的组件。 DefaultBandwidthMeter实现了BandwidthMeterTransferListener接口。

您应该只使用一个DefaultBandwidthMeter实例并将其传递给AdaptiveTrackSelection.Factory(作为BandwidthMeter)和DefaultDataSourceFactory(作为TransferListener)。这样,在数据源中完成的测量在轨道选择器中生效。

将代码放在您传递给AdaptiveTrackSelection.Factory的实例上方,不知道计量的是什么,根据您描述的内容显然不起作用。

另请注意,如果您创建新的DefaultBandwidthMeter实例,则到目前为止完成的测量将丢失。因此,您可能希望将DefaultBandwidthMeter作为静态变量等来保留早期播放的计量。

TrackSelection.Factory videoTrackSelectionFactory =
    new AdaptiveTrackSelection.Factory(DEFAULT_BANDWIDTH_METER);
TrackSelector trackSelector =
    new DefaultTrackSelector(videoTrackSelectionFactory);

DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
    Util.getUserAgent(context, "yourApplicationName"), DEFAULT_BANDWIDTH_METER);

另见how the PlayerActivity of the demo application does it

答案 1 :(得分:1)

在我的情况下,带宽改变时并没有切换轨迹,因此我将DefaultHttpDataSourceFactory替换为OkHttpDataSourceFactory并添加了依赖性:

这是代码段:

implementation 'com.google.android.exoplayer:extension-okhttp:2.12.1'

val httpCallFactory = OkHttpClient.Builder()
            .writeTimeout(httpWriteTimeout, TimeUnit.MILLISECONDS)
            .readTimeout(httpReadTimeout, TimeUnit.MILLISECONDS)
            .connectTimeout(httpConnectTimeout, TimeUnit.MILLISECONDS)
            .build()
        val dataSourceFactory = OkHttpDataSourceFactory(
            httpCallFactory,
            userAgent,
            transferListener
        )

        /* val dataSourceFactory = DefaultHttpDataSourceFactory(
             userAgent,
             transferListener,
             DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
             DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
             true
         )*/
        val mediaSource: MediaSource = buildMediaSource(Uri.parse(url), dataSourceFactory)
        exoPlayer.setMediaSource(mediaSource, resetPosition)
        exoPlayer.prepare()