9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android ExoPlayer + HLS + IMA

Last updated at Posted at 2018-02-09

#Android ExoPlayer + HLS + Google IMA

###はじめに
こんにちは streampack チームのメディです。
https://cloudpack.jp/service/option/streampack.html

Objective: ・目的
Play a HLS stream in an Android APP with ExoPlayer & display Google IMA advertisements.
ExoPlayerを使用してAndroidアプリでHLSストリームを再生し、Google IMA広告を表示します。
##Implementation・ 実装

###Step 0
HLS
If you don't have a HLS stream, please visit the following page to find one.
HLSストリームがない場合は、以下のページをご覧ください。
https://github.com/notanewbie/LegalStream

IMA
If you don't have IMA credentials, you can use demo tags.
IMA資格情報がない場合は、デモタグを使用できます。
https://developers.google.com/interactive-media-ads/docs/sdks/html5/tags

###Step 1
Create a new project & a blank Main Activity.
新しいプロジェクトと空白のメインアクティビティを作成してください。

MainActivity.java

package jp.co.mycompany.com.exotuto;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

####AndroidManifest.xml
Enable hardware acceleration.
ハードウェアアクセラレーションを有効にしてください。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.co.mycompany.com.exotuto">

    <application
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

####Dependencies ・ソフトウェアの依存関係
buid.gradle(Module:app)


apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "jp.co.mycompany.com.exotuto"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    compile 'com.google.android.exoplayer:exoplayer:2.6.0'
    compile 'com.google.android.exoplayer:exoplayer-hls:2.6.0'
    compile 'com.google.android.exoplayer:extension-ima:2.6.0'
}

###Step 2
Create a new Basic Activity & name it PlayerActivity.
新しいBasicアクティビティを作成し、それをPlayerActivityと名づけます。

Screen Shot 2018-01-09 at 12.06.36.png

Then modify MainActivity.java as follows:
MainActivity.java を次のように変更します。


public class MainActivity extends AppCompatActivity {

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

        Intent intent = new Intent(this, PlayerActivity.class);
        startActivity(intent);


    }
}

###Step 3
####Simple HLS implementation・ 単純なHLS実装

res/layout/content_player.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="jp.co.mycompany.com.exotuto.PlayerActivity"
    tools:showIn="@layout/activity_player">

    <com.google.android.exoplayer2.ui.SimpleExoPlayerView
        android:id="@+id/player_view"
        android:focusable="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dp" />

</android.support.constraint.ConstraintLayout>

PLayerActivity.java


public class PlayerActivity extends AppCompatActivity {

    //Player
    private SimpleExoPlayerView simpleExoPlayerView;
    private SimpleExoPlayer player;

    //Logs
    final private String TAG = "PlayerActivity";

    //HLS
    final private String VIDEO_URL = "https://nhkworld.webcdn.stream.ne.jp/www11/nhkworld-tv/domestic/263942/live_wa_s.m3u8";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_player);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

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

        // Create a default LoadControl
        LoadControl loadControl = new DefaultLoadControl();
        //Bis. Create a RenderFactory
        RenderersFactory renderersFactory = new DefaultRenderersFactory(this);

        //Create the player
        player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector, loadControl);
        simpleExoPlayerView = new SimpleExoPlayerView(this);
        simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);


        //Set media controller
        simpleExoPlayerView.setUseController(true);
        simpleExoPlayerView.requestFocus();

        // Bind the player to the view.
        simpleExoPlayerView.setPlayer(player);

        // Set the media source
        Uri mp4VideoUri = Uri.parse(VIDEO_URL);

        //Measures bandwidth during playback. Can be null if not required.
        DefaultBandwidthMeter bandwidthMeterA = new DefaultBandwidthMeter();

        //Produces DataSource instances through which media data is loaded.
        DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "PiwikVideoApp"), bandwidthMeterA);

        //Produces Extractor instances for parsing the media data.
        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

        //FOR LIVE STREAM LINK:
        MediaSource videoSource = new HlsMediaSource(mp4VideoUri, dataSourceFactory, 1, null, null);
        final MediaSource mediaSource = videoSource;


        player.prepare(videoSource);


    }

    //Android Life cycle
    @Override
    protected void onStop() {
        player.release();
        super.onStop();
        Log.v(TAG, "onStop()...");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.v(TAG, "onStart()...");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.v(TAG, "onResume()...");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.v(TAG, "onPause()...");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy()...");
        player.release();
    }



}

Please run your app in the Android emulator.
Androidエミュレータでアプリをテストしてください。

Screen Shot 2018-01-09 at 18.52.34.png

###Step 4
####Player listeners ・プレーヤーリスナー
In the onCreate method of PlayerActivity.java, please add the following listeners.
PlayerActivityのonCreateメソッドで使用します。次のリスナーを追加してください。

//ExoPLayer events listener
        player.addListener(new Player.EventListener() {

            @Override
            public void onTimelineChanged(Timeline timeline, Object manifest) {
                Log.v(TAG, "Listener-onTimelineChanged...");
            }

            @Override
            public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
                Log.v(TAG, "Listener-onTracksChanged...");
            }

            @Override
            public void onLoadingChanged(boolean isLoading) {
                Log.v(TAG, "Listener-onLoadingChanged...isLoading:" + isLoading);
            }

            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                Log.v(TAG, "Listener-onPlayerStateChanged..." + playbackState);

                switch (playbackState) {


                    case Player.STATE_IDLE:
                        Log.v(TAG, "STATE IDLE");
                        break;

                    case Player.STATE_BUFFERING:
                        Log.v(TAG, "STATE BUFFERING");
                        break;

                    case Player.STATE_READY:
                        Log.v(TAG, "STATE READY");
                        break;

                    case Player.STATE_ENDED:
                        Log.v(TAG, "STATE ENDED");
                        break;

                    default:
                        break;
                }
            }

            @Override
            public void onRepeatModeChanged(int repeatMode) {
                Log.v(TAG, "Listener-onRepeatModeChanged...");
            }

            @Override
            public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {
                Log.v(TAG, "Listener-onPlayerError...");
                player.stop();
                player.prepare(adsMediaSource);
                player.setPlayWhenReady(true);

            }

            @Override
            public void onPositionDiscontinuity(int reason) {
                Log.v(TAG, "Listener-onPositionDiscontinuity...");

            }

            @Override
            public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
                Log.v(TAG, "Listener-onPlaybackParametersChanged...");
            }

            @Override
            public void onSeekProcessed() {

            }
        });

###Step 5
####IMA implementation ・IMAの実装

In PlayerActivity.java, add the following class variables.
PlayerActivity.java で、次のクラス変数を追加してください。

//IMA
private ImaAdsLoader imaAdsLoader;
final private String AD_TAG_URI = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator=";

Please update the onCreate method of PlayerActivity.java as follows.
PlayerActivity.java のonCreateメソッドを次のように更新してください。

         //player.prepare(adsMediaSource);//Remove this line.

        imaAdsLoader = new ImaAdsLoader(this, Uri.parse(AD_TAG_URI));

        AdsMediaSource.AdsListener adsListener = new AdsMediaSource.AdsListener() {
            @Override
            public void onAdLoadError(IOException error) {
                error.printStackTrace();
            }

            @Override
            public void onAdClicked() {

            }

            @Override
            public void onAdTapped() {

            }
        };
        AdsMediaSource adsMediaSource = new AdsMediaSource(
                mediaSource,
                dataSourceFactory,
                imaAdsLoader,
                simpleExoPlayerView.getOverlayFrameLayout(),
                null,
                adsListener
        );

        player.prepare(adsMediaSource);

####Results 結果
It works!
できます!
Screen Shot 2018-01-09 at 19.02.17.png

###Step 6
####Adding IMA event listeners ・IMAイベントリスナーの追加
Please add the following code to the onCreate method of PlayerActivity.java.
PlayerActivity.javaのonCreateメソッドに次のコードを追加してください。

 //IMA event listeners
        com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader = imaAdsLoader.getAdsLoader();
        adsLoader.addAdsLoadedListener(new AdsLoader.AdsLoadedListener() {
            @Override
            public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) {

                AdsManager imaAdsManager = adsManagerLoadedEvent.getAdsManager();
                imaAdsManager.addAdEventListener(new AdEvent.AdEventListener() {
                    @Override
                    public void onAdEvent(AdEvent adEvent) {
                        Log.v("AdEvent: ", adEvent.getType().toString());
                        switch (adEvent.getType()) {
                            case LOADED:
                                break;

                            case PAUSED:
                                break;

                            case STARTED:
                                break;

                            case COMPLETED:
                                break;

                            case ALL_ADS_COMPLETED:
                                break;

                            default:
                                break;


                        /*    Full list of events. Implement what you need.

                        LOADED, TAPPED, PAUSED, LOG, CLICKED, RESUMED, SKIPPED, STARTED, MIDPOINT,
                        COMPLETED, AD_PROGRESS, ICON_TAPPED, AD_BREAK_ENDED, AD_BREAK_READY,
                        FIRST_QUARTILE, THIRD_QUARTILE, AD_BREAK_STARTED, ALL_ADS_COMPLETED,
                        CUEPOINTS_CHANGED, CONTENT_PAUSE_REQUESTED,CONTENT_RESUME_REQUESTED

                        */
                        }

                    }
                });

            }
        });

Full project code

###Information sources・ 情報源
https://github.com/sakurabird/Android-Example-HLS-ExoPlayer
https://developers.google.com/interactive-media-ads/docs/sdks/android/
https://github.com/google/ExoPlayer
https://google.github.io/ExoPlayer/demo-application.html

9
2
30

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?