简体   繁体   English

Exoplayer自适应hls流媒体

[英]Exoplayer adaptive hls streaming

I am looking for good and simple example/explanation how to implement ExoPlayer for HLS Adaptive streaming. 我正在寻找好的和简单的示例/解释如何实现ExoPlayer for HLS Adaptive streaming。 I am a newbie and do not have experience and knowledge so I can figure how to do this from code example on git. 我是一个新手,没有经验和知识,所以我可以从git上的代码示例中找到如何做到这一点。

There are too many 'moving parts' so beginner can understand and reuse it in own projects. 有太多的“活动部件”,所以初学者可以理解并在自己的项目中重复使用它。

Can somebody help me to learn and understand how to use/implement ExoPlayer in order to achieve this functionality? 有人可以帮助我学习和理解如何使用/实现ExoPlayer以实现此功能吗?

Thanks! 谢谢!

The easiest way to get started using ExoPlayer is to add it as a gradle dependency. 开始使用ExoPlayer的最简单方法是将其添加为gradle依赖项。 You need to make sure you have the jcenter repository included in the build.gradle file in the root of your project: 您需要确保在项目的根目录中的build.gradle文件中包含jcenter存储库:

repositories { jcenter() }

Next, include the following in your module's build.gradle file: 接下来,在模块的build.gradle文件中包含以下内容:

compile 'com.google.android.exoplayer:exoplayer:r2.2.0'

1. Your Layout File 1.您的布局文件

    <?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.exoplayer2.ui.SimpleExoPlayerView
        android:id="@+id/player_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
        app:resize_mode="fill"/>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="gone"/>

</FrameLayout>

2. Your Class File(Activity) 2.你的班级档案(活动)

    public class VideoPlayerActivity extends AppCompatActivity implements ExoPlayer.EventListener {

    private SimpleExoPlayerView simpleExoPlayerView;
    private String hlsVideoUri = "http://playertest.longtailvideo.com/adaptive/bbbfull/bbbfull.m3u8";
    private SimpleExoPlayer player;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_player);

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

        // 2. Create a default LoadControl
        LoadControl loadControl = new DefaultLoadControl();


        // 3. Create the player
        player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);

        simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
        simpleExoPlayerView.setPlayer(player);

        // Measures bandwidth during playback. Can be null if not required.
        DefaultBandwidthMeter defaultBandwidthMeter = new DefaultBandwidthMeter();
        // Produces DataSource instances through which media data is loaded.
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this,
                Util.getUserAgent(this, "Exo2"), defaultBandwidthMeter);
        // Produces Extractor instances for parsing the media data.
        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
        // This is the MediaSource representing the media to be played.
        HlsMediaSource hlsMediaSource = new HlsMediaSource(Uri.parse(hlsVideoUri), dataSourceFactory, mainHandler, new AdaptiveMediaSourceEventListener() {
            @Override
            public void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs) {

            }

            @Override
            public void onLoadCompleted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {

            }

            @Override
            public void onLoadCanceled(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {

            }

            @Override
            public void onLoadError(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded, IOException error, boolean wasCanceled) {

            }

            @Override
            public void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs) {

            }

            @Override
            public void onDownstreamFormatChanged(int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaTimeMs) {

            }
        });

        player.addListener(this);
        player.prepare(hlsMediaSource);
        simpleExoPlayerView.requestFocus();
        player.setPlayWhenReady(true);

        progressBar = (ProgressBar) findViewById(R.id.progressBar);
    }

    @Override
    public void onTimelineChanged(Timeline timeline, Object manifest) {

    }

    @Override
    public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

    }

    @Override
    public void onLoadingChanged(boolean isLoading) {

    }

    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

        switch (playbackState) {
            case Player.STATE_BUFFERING:
                //You can use progress dialog to show user that video is preparing or buffering so please wait
                progressBar.setVisibility(View.VISIBLE);
                break;
            case Player.STATE_IDLE:
                //idle state
                break;
            case Player.STATE_READY:
                // dismiss your dialog here because our video is ready to play now
                progressBar.setVisibility(View.GONE);
                break;
            case Player.STATE_ENDED:
                // do your processing after ending of video
                break;
        }
    }

    @Override
    public void onPlayerError(ExoPlaybackException error) {

        AlertDialog.Builder adb = new AlertDialog.Builder(VideoPlayerActivity.this);
        adb.setTitle("Could not able to stream video");
        adb.setMessage("It seems that something is going wrong.\nPlease try again.");
        adb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                finish(); // take out user from this activity. you can skip this
            }
        });
        AlertDialog ad = adb.create();
        ad.show();
    }

    @Override
    public void onPositionDiscontinuity() {

    }

    @Override
    protected void onPause() {
        super.onPause();
        if (player != null) {
            player.setPlayWhenReady(false); //to pause a video because now our video player is not in focus
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        player.release();
    }
}

I think this is enough for beginner. 我认为这对初学者来说已经足够了。 Also keep in mind that this library's standard audio and video components rely on Android's MediaCodec API, which was released in Android 4.1 (API level 16). 另请注意,此库的标准音频和视频组件依赖于Android的MediaCodec API,该API是在Android 4.1(API级别16)中发布的。 So it will not work on android 4.0 and below. 因此它不适用于Android 4.0及更低版本。

Don't forget to add this permission to the manifest file : 不要忘记将此权限添加到manifest file

<uses-permission android:name="android.permission.INTERNET"/>

The answer from @Vicky will work, but has one flaw. @Vicky的答案可行,但有一个缺陷。

The bandwidth meter that you pass to the track selector must be the same one that the datasource factory uses. 传递给轨道选择器的带宽计必须与数据源工厂使用的带宽计相同。 The data source factory maintains the bandwidth estimate by calling the BW meter methods, and the adaptive track selection process gets the estimate to decide which track to adapt to. 数据源工厂通过调用BW计量器方法来维持带宽估计,并且自适应轨道选择过程获得估计以决定适应哪个轨道。

If they are not the same instance, the adaptive selection always gets -1 as the BW, and picks some middle ground option. 如果它们不是同一个实例,则自适应选择总是得到-1作为BW,并选择一些中间地面选项。

The demo ExoPlayer apps also have this flaw. 演示ExoPlayer应用程序也有这个缺陷。 They pass false to the useBwMeter in buildDataSource(), which means no updating of the BW estimate EDIT: Actually, this BW meter is for the manifest loader. 它们将false传递给buildDataSource()中的useBwMeter,这意味着不会更新BW估计编辑:实际上,此BW计量器用于清单加载器。 It does not need to use the BW meter. 它不需要使用BW仪表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM