ExoPlayer无法使用广告

时间:2018-01-22 17:14:56

标签: android ads exoplayer

我已经使用Codelab中的示例在我的应用程序中实现了ExoPlayer:https://codelabs.developers.google.com/codelabs/exoplayer-intro/#3,algo和https://medium.com/google-exoplayer/playing-ads-with-exoplayer-and-ima-868dfd767ea中的示例,唯一的区别是我使用AdsMediaSource代替已弃用ImaAdsMediaSource。 我的实现是这样的:

class HostVideoFullFragment : Fragment(), AdsMediaSource.MediaSourceFactory {

    override fun getSupportedTypes() = intArrayOf(C.TYPE_DASH, C.TYPE_HLS, C.TYPE_OTHER)

    override fun createMediaSource(uri: Uri?, handler: Handler?, listener: MediaSourceEventListener?): MediaSource {
        @C.ContentType val type = Util.inferContentType(uri)
        return when (type) {
            C.TYPE_DASH -> {
                DashMediaSource.Factory(
                        DefaultDashChunkSource.Factory(mediaDataSourceFactory),
                        manifestDataSourceFactory)
                        .createMediaSource(uri, handler, listener)
            }

            C.TYPE_HLS -> {
                HlsMediaSource.Factory(mediaDataSourceFactory)
                        .createMediaSource(uri, handler, listener)
            }

            C.TYPE_OTHER -> {
                ExtractorMediaSource.Factory(mediaDataSourceFactory)
                        .createMediaSource(uri, handler, listener)
            }

            else -> throw IllegalStateException("Unsupported type for createMediaSource: $type")
        }
    }

    private var player: SimpleExoPlayer? = null
    private lateinit var playerView: SimpleExoPlayerView
    private lateinit var binding: FragmentHostVideoFullBinding

    private var playbackPosition: Long = 0
    private var currentWindow: Int = 0
    private var playWhenReady = true

    private var inErrorState: Boolean = false

    private lateinit var adsLoader: ImaAdsLoader
    private lateinit var manifestDataSourceFactory: DataSource.Factory
    private lateinit var mediaDataSourceFactory: DataSource.Factory

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //Initialize the adsLoader
        adsLoader = ImaAdsLoader(activity as Context, Uri.parse("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%3Dpremidpost&cmsid=496&vid=short_onecue&correlator="))

        manifestDataSourceFactory = DefaultDataSourceFactory(
                context, Util.getUserAgent(context, "BUO-APP"))//TODO change the applicationName with the right application name
//
        mediaDataSourceFactory = DefaultDataSourceFactory(
                context,
                Util.getUserAgent(context, "BUO-APP"),//TODO change the applicationName with the right application name
                DefaultBandwidthMeter())
    }

    private fun initializePlayer() {
        /*
        * Since the player can change from null (when we release resources) to not null we have to check if it's null.
        * If it is then reset again
        * */
        if (player == null) {
            //Initialize the Exo Player
            player = ExoPlayerFactory.newSimpleInstance(DefaultRenderersFactory(activity as Context),
                    DefaultTrackSelector())
        }

        val uri = Uri.parse(videoURl)

        val mediaSourceWithAds = buildMediaSourceWithAds(uri)

        //Bind the view from the xml to the SimpleExoPlayer instance
        playerView.player = player

        //Add the listener that listens for errors
        player?.addListener(PlayerEventListener())

        player?.seekTo(currentWindow, playbackPosition)

        player?.prepare(mediaSourceWithAds, true, false)

        //In case we could not set the exo player
        player?.playWhenReady = playWhenReady

        //We got here without an error, therefore set the inErrorState as false
        inErrorState = false

        //Re update the retry button since, this method could have come from a retry click
        updateRetryButton()
    }

    private inner class PlayerEventListener : Player.DefaultEventListener() {

        fun updateResumePosition() {
            player?.let {
                currentWindow = player!!.currentWindowIndex
                playbackPosition = Math.max(0, player!!.contentPosition)
            }
        }

        override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
            //The player state has ended
            //TODO check if there is going to be a UI change here
//            if (playbackState == Player.STATE_ENDED) {
//                showControls()
//            }
//            updateButtonVisibilities()
        }

        override fun onPositionDiscontinuity(@Player.DiscontinuityReason reason: Int) {
            if (inErrorState) {
                // This will only occur if the user has performed a seek whilst in the error state. Update
                // the resume position so that if the user then retries, playback will resume from the
                // position to which they seek.
                updateResumePosition()
            }
        }

        override fun onPlayerError(e: ExoPlaybackException?) {

            var errorString: String? = null

            //Check what was the error so that we can show the user what was the correspond problem
            if (e?.type == ExoPlaybackException.TYPE_RENDERER) {
                val cause = e.rendererException
                if (cause is MediaCodecRenderer.DecoderInitializationException) {
                    // Special case for decoder initialization failures.
                    errorString = if (cause.decoderName == null) {
                        when {
                            cause.cause is MediaCodecUtil.DecoderQueryException -> getString(R.string.error_querying_decoders)
                            cause.secureDecoderRequired -> getString(R.string.error_no_secure_decoder,
                                    cause.mimeType)
                            else -> getString(R.string.error_no_decoder,
                                    cause.mimeType)
                        }
                    } else {
                        getString(R.string.error_instantiating_decoder,
                                cause.decoderName)
                    }
                }
            }

            if (errorString != null) {
                //Show the toast with the proper error
                Toast.makeText(activity as Context, errorString, Toast.LENGTH_LONG).show()
            }

            inErrorState = true

            if (isBehindLiveWindow(e)) {
                clearResumePosition()
                initializePlayer()
            } else {
                updateResumePosition()
                updateRetryButton()
            }
        }
    }

    private fun clearResumePosition() {
        //Clear the current resume position, since there was an error
        currentWindow = C.INDEX_UNSET
        playbackPosition = C.TIME_UNSET
    }

    /*
    * This is for the multi window support
    * */
    private fun isBehindLiveWindow(e: ExoPlaybackException?): Boolean {
        if (e?.type != ExoPlaybackException.TYPE_SOURCE) {
            return false
        }
        var cause: Throwable? = e.sourceException
        while (cause != null) {
            if (cause is BehindLiveWindowException) {
                return true
            }
            cause = cause.cause
        }
        return false
    }

    private fun buildMediaSourceWithAds(uri: Uri): MediaSource {


        /*
        * This content media source is the video itself without the ads
        * */
        val contentMediaSource = ExtractorMediaSource.Factory(
                DefaultHttpDataSourceFactory("BUO-APP")).createMediaSource(uri) //TODO change the user agent

        /*
        * The method constructs and returns a ExtractorMediaSource for the given uri.
        * We simply use a new DefaultHttpDataSourceFactory which only needs a user agent string.
        * By default the factory will use a DefaultExtractorFactory for the media source.
        * This supports almost all non-adaptive audio and video formats supported on Android. It will recognize our mp3 file and play it nicely.
        * */
        return AdsMediaSource(
                contentMediaSource,
                /* adMediaSourceFactory= */ this,
                adsLoader,
                playerView.overlayFrameLayout,
                /* eventListener= */ null, null)
    }

    override fun onStart() {
        super.onStart()

        if (Util.SDK_INT > 23) {
            initializePlayer()
        }
    }

    override fun onResume() {
        super.onResume()
        hideSystemUi()

        /*
        * Starting with API level 24 Android supports multiple windows.
        * As our app can be visible but not active in split window mode, we need to initialize the player in onStart.
        * Before API level 24 we wait as long as possible until we grab resources, so we wait until onResume before initializing the player.
        * */
        if ((Util.SDK_INT <= 23 || player == null)) {
            initializePlayer()
        }
    }
}

广告从不显示,如果显示,则会显示从不允许视频显示的呈现错误E/ExoPlayerImplInternal: Renderer error.。我运行了IMA广告https://developers.google.com/interactive-media-ads/docs/sdks/android/示例代码中的示例,但它既不起作用也不起作用。有没有人用最新的ExoPlayer库版本成功实现了Exo Player? 请帮忙。谢谢!

2 个答案:

答案 0 :(得分:1)

在模拟器上时,请确保在虚拟设备上启用gpu呈现

答案 1 :(得分:0)

问题是模拟器无法呈现视频。因此,它没有显示广告或视频。在手机上运行该应用程序即可运行