【问题标题】:Exoplayer adaptive hls streamingExoplayer 自适应 hls 流式传输
【发布时间】:2017-07-02 21:22:18
【问题描述】:

我正在寻找如何为HLS Adaptive 流实现ExoPlayer 的良好而简单的示例/说明。我是新手,没有经验和知识,所以我可以从 git 上的代码示例中弄清楚如何做到这一点。

“活动部件”太多了,所以初学者可以理解并在自己的项目中重用它。

有人可以帮助我学习和理解如何使用/实现ExoPlayer 以实现此功能吗?

谢谢!

【问题讨论】:

    标签: android http-live-streaming exoplayer adaptive-bitrate


    【解决方案1】:

    开始使用 ExoPlayer 的最简单方法是将其添加为 gradle 依赖项。您需要确保在项目根目录的 build.gradle 文件中包含 jcenter 存储库:

    repositories { jcenter() }

    接下来,在模块的 build.gradle 文件中包含以下内容:

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

    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。你的类文件(活动)

        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();
        }
    }
    

    我认为这对初学者来说已经足够了。另外请记住,该库的标准音频和视频组件依赖于 Android 的 MediaCodec API,该 API 在 Android 4.1(API 级别 16)中发布。所以它在android 4.0及以下版本上不起作用。

    不要忘记将此权限添加到manifest file

    &lt;uses-permission android:name="android.permission.INTERNET"/&gt;

    【讨论】:

    • 谢谢你,维姬!请告诉exoplayer是否会根据带宽自动选择视频质量?我看到必须实现的方法,但我不明白如何使用它?请和我一起裸露。谢谢:)
    • Exoplayer 会根据带宽自动选择视频。您不必为此担心。
    • 您收到BehindLiveWindowException 获取此代码了吗?我看到github 上有一个关于这个问题的错误。我有来自ExoPlayer.EventListener 接口的覆盖方法onPlayerError 但没有运气。有什么建议吗?
    • 当然,这里是我实现的viewModel类player
    • 我认为这是一个错误,在 github 上他们告诉重新初始化媒体源,你已经这样做了。
    【解决方案2】:

    @Vicky 的回答可以,但有一个缺陷。

    您传递给轨道选择器的带宽计量器必须与数据源工厂使用的相同。数据源工厂通过调用 BW Meter 方法来维护带宽估计,自适应轨道选择过程得到估计来决定适应哪个轨道。

    如果它们不是同一个实例,则自适应选择总是得到 -1 作为 BW,并选择一些中间选项。

    ExoPlayer 演示应用也有这个缺陷。他们将 false 传递给 buildDataSource() 中的 useBwMeter,这意味着不更新 BW 估计值编辑:实际上,此 BW 计量器用于清单加载程序。它不需要使用BW Meter。

    【讨论】:

    • 有没有办法通过exo播放器实现RTMP自适应流媒体?
    猜你喜欢
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多