如何将 Google Cast v3 与 ExoPlayer v2 集成?

问题描述 投票:0回答:3

如何将 Google Cast v3 与 ExoPlayer v2 完全集成?该活动将包含一个

FrameLayout
,其中包含一个
com.google.android.exoplayer2.ui.SimpleExoPlayerView
Google 教程 仅涵盖与
VideoView
的集成。

android google-cast exoplayer
3个回答
4
投票

下面的代码可在本 Gist 的 Kotlin 类中找到,它应该可以帮助人们第一次尝试设置他们的 CastPlayer:

https://gist.github.com/stefan-zh/fd52e0ee06088ac4086d2ea3fb7d7f3e

此外,阅读 Google 的本教程会对您有所帮助:https://codelabs.developers.google.com/codelabs/cast-videos-android/index.html#0

我还使用了本教程来开始:https://android.jlelse.eu/sending-media-to-chromecast-has-never-been-easier-c331eeef1e0a


这里详细介绍了如何使用 ExoPlayer 及其 Cast 扩展来实现此目的。

1.您将需要这些依赖项:

// ExoPlayer is an advanced media player for playing media files
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
implementation "com.google.android.exoplayer:extension-cast:$exoplayer_version"

2.您将需要“投射”按钮

可以在活动的选项菜单中添加“投射”按钮。这是推荐的方法。

将以下内容添加到

res/menu/browse.xml
(在我的例子中,菜单文件称为
browse.xml
):

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" >
    <item
        android:id="@+id/media_route_menu_item"
        android:title="@string/media_route_menu_title"
        app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
        app:showAsAction="always"/>
</menu>

然后将以下代码添加到您的 Activity 以启用

castButton
:

/**
 * We need to populate the Cast button across all activities as suggested by Google Cast Guide:
 * https://developers.google.com/cast/docs/design_checklist/cast-button#sender-cast-icon-available
 */
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val result = super.onCreateOptionsMenu(menu)
   menuInflater.inflate(R.menu.browse, menu)
   castButton = CastButtonFactory.setUpMediaRouteButton(applicationContext, menu, R.id.media_route_menu_item)
   return result
}

3.为 Cast 上下文声明您的选项提供程序

您需要这个才能获得包含可以投射到的设备列表的选项对话框。将其添加到您的

AndroidManifest.xml
标签中的
application

<meta-data
   android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
   android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider" />

4.您的 Activity 需要实现 ExoPlayer 的 Cast Extension 接口
SessionAvailabilityListener

此界面将允许您监听 Cast 会话可用性的变化。根据 Cast 会话是否可用,您可以将播放直接播放到本地播放器或远程播放器。

override fun onCastSessionAvailable() {
    playOnPlayer(castPlayer)
}

override fun onCastSessionUnavailable() {
    playOnPlayer(exoPlayer)
}

5.您将需要逻辑来初始化玩家:

注意我们如何调用

castPlayer?.setSessionAvailabilityListener(this)
,其中
this
指的是实现
SessionAvailabilityListener
接口的 Activity。当 Cast 会话可用性发生变化时,将调用侦听器的方法。

private fun initializePlayers() {
    exoPlayer = SimpleExoPlayer.Builder(this).build()
    playerView.player = exoPlayer

    if (castPlayer == null) {
        castPlayer = CastPlayer(castContext)
        castPlayer?.setSessionAvailabilityListener(this)
    }

    // start the playback
    if (castPlayer?.isCastSessionAvailable == true) {
        playOnPlayer(castPlayer)
    } else {
        playOnPlayer(exoPlayer)
    }
}

6.您需要逻辑来在选定的播放器上播放:

  • 此方法允许您存储播放状态(
    playbackPosition
    playWhenReady
    windowIndex
  • 为本地或远程播放器创建正确的媒体类型
  • 选择哪个播放器应开始播放

playOnPlayer()方法:

private fun playOnPlayer(player: Player?) {
    if (currentPlayer == player) {
        return
    }

    // save state from the existing player
    currentPlayer?.let {
        if (it.playbackState != Player.STATE_ENDED) {
            it.rememberState()
        }
        it.stop(true)
    }

    // set the new player
    currentPlayer = player

    // set up the playback
    // if the current player is the ExoPlayer, play from it
    if (currentPlayer == exoPlayer) {
        // build the MediaSource from the URI
        val uri = Uri.parse(videoClipUrl)
        val dataSourceFactory = DefaultDataSourceFactory(this@SampleCastingPlayerActivity, "exoplayer-agent")
        val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri)

        // use stored state (if any) to resume (or start) playback
        exoPlayer?.playWhenReady = playWhenReady
        exoPlayer?.seekTo(currentWindow, playbackPosition)
        exoPlayer?.prepare(mediaSource, false, false)
    }

    // if the current player is the CastPlayer, play from it
    if (currentPlayer == castPlayer) {
        val metadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
        metadata.putString(MediaMetadata.KEY_TITLE, "Title")
        metadata.putString(MediaMetadata.KEY_SUBTITLE, "Subtitle")
        metadata.addImage(WebImage(Uri.parse("any-image-url")))

        val mediaInfo = MediaInfo.Builder(videoClipUrl)
            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
            .setContentType(MimeTypes.VIDEO_MP4)
            .setMetadata(metadata)
            .build()
        val mediaItem = MediaQueueItem.Builder(mediaInfo).build()
        castPlayer?.loadItem(mediaItem, playbackPosition)
    }
}

7.记住状态并清理资源

每次在后台或前台之间切换应用程序时,您都需要释放或请求资源。每次将播放器的资源释放回系统时,您都需要保存其状态。

/**
 * Remembers the state of the playback of this Player.
 */
private fun Player.rememberState() {
    [email protected] = playWhenReady
    [email protected] = currentPosition
    [email protected] = currentWindowIndex
}

/**
 * Releases the resources of the local player back to the system.
 */
private fun releaseLocalPlayer() {
    exoPlayer?.release()
    exoPlayer = null
    playerView.player = null
}

/**
 * Releases the resources of the remote player back to the system.
 */
private fun releaseRemotePlayer() {
    castPlayer?.setSessionAvailabilityListener(null)
    castPlayer?.release()
    castPlayer = null
}

0
投票

Google Cast SDK 独立于本地播放器,您可以使用

ExoPlayer
MediaPlayer
(
VideoView
)

一旦您的应用程序有活动会话,请将网址放入

MediaInfo

val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)

movieMetadata.putString(MediaMetadata.KEY_TITLE, "Title")
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, "Sub")

val mediaLoadOptions =  MediaInfo.Builder( < URL > )
     .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
     .setContentType(< Content Type of Media>)
     .setMetadata(movieMetadata)
     .setStreamDuration(<Media Duration >)
     .build()

mCastSession.remoteMediaClient.load(buildMediaInfo(url), mediaLoadOptions)

如果您需要流式传输本地媒体,则需要使用 NanoHttpd 或您选择的其他方式自行流式传输,并实现 Cast Receiver


0
投票

一切正常,我唯一需要改变的是

 castPlayer?.loadItem(mediaItem, playbackPosition)

castPlayer?.setMediaItem(mediaItem)

因为我找不到 loadItem 方法。

© www.soinside.com 2019 - 2024. All rights reserved.