web-dev-qa-db-fra.com

Exoplayer Adaptive HL Streaming

Je recherche un exemple/explication simple et efficace sur la façon d'implémenter ExoPlayer pour HLS Adaptive diffusion. Je suis un débutant et je n'ai pas d'expérience et de connaissances, je peux donc comprendre comment le faire à partir de l'exemple de code sur git.

Il y a trop de "pièces mobiles" pour que le débutant puisse le comprendre et le réutiliser dans ses propres projets.

Quelqu'un peut-il m'aider à apprendre et à comprendre comment utiliser/implémenter ExoPlayer pour obtenir cette fonctionnalité?

Merci!

10
svarog

La façon la plus simple de commencer à utiliser ExoPlayer est de l'ajouter en tant que dépendance gradle. Vous devez vous assurer que le référentiel jcenter est inclus dans le fichier build.gradle à la racine de votre projet:

repositories { jcenter() }

Ensuite, incluez les éléments suivants dans le fichier build.gradle de votre module:

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

1. Votre fichier de mise en page

    <?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. Votre fichier de classe (activité)

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

Je pense que cela suffit pour les débutants. Gardez également à l'esprit que les composants audio et vidéo standard de cette bibliothèque reposent sur l'API MediaCodec d'Android, qui a été publiée dans Android 4.1 (API niveau 16). Cela ne fonctionnera donc pas sur Android 4.0 et inférieur.

N'oubliez pas d'ajouter cette autorisation au manifest file:

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

16
Vicky

La réponse de @Vicky fonctionnera, mais a un défaut.

Le compteur de bande passante que vous passez au sélecteur de piste doit être le même que celui utilisé par la fabrique de sources de données. La fabrique de sources de données maintient l'estimation de la bande passante en appelant les méthodes du compteur BW, et le processus de sélection de piste adaptative obtient l'estimation pour décider à quelle piste s'adapter.

S'ils ne sont pas la même instance, la sélection adaptative obtient toujours -1 comme BW et choisit une option intermédiaire.

Les applications de démonstration ExoPlayer ont également cette faille. Ils passent false à useBwMeter dans buildDataSource (), ce qui signifie aucune mise à jour de l'estimation BW EDIT: En fait, ce compteur BW est destiné au chargeur de manifestes. Il n'a pas besoin d'utiliser le compteur BW.

3
Darren