web-dev-qa-db-ja.com

Exoplayerのフルスクリーン

RecyclerViewおよびViewPagerexoplayerを使用してショービデオ(.mp4)を表示しようとしています。カスタムレイアウトのビデオコントローラーを表示します。ここまでは順調ですね。

今度は他のビデオプレーヤーと同じようにビデオを全画面表示してみてくださいexoplayerドキュメントで良い方法を見つけることができません。

誰かが私を助けてくれますか?

11
Ashkan

ExoPlayerライブラリは現在、フルスクリーンモードを有効/無効にする組み込みの方法を提供していません。これを自分で実装するか、このためのサードパーティのコードを見つける必要があります。

基本的に2つのステップが必要です

a)ウィンドウとアクティビティのプロパティをフルスクリーンモードまたはイマーシブモードに設定し、(必要に応じて)横長モードに変更します。それは難しくありません。 Android Developers のこのページ)を参照してください。

b)イマーシブモードでビューポート全体をカバーするSimpleExoPlayerView(実際はサーフェスに関するもの)へのレンダリングの遷移。これは、すべてのAPIレベルで最適なユーザーエクスペリエンスを実現するための課題です。

最適なユーザーエクスペリエンスを実現するために、全画面表示への移行中も再生中もプレーヤーを再生し続け、シームレスに再生を続けたいと考えています。 RecyclerViewでは、これはすべてのAPIレベルで解決するのが少し難しいです。

アプローチ1

最も簡単な方法は、おそらく、没入モードに入るとすぐにレイアウトの上に配置するSimpleExoPlayerViewの個別のインスタンスを作成することです(このための2番目のビューでダイアログを開く人もいれば、2番目のビューをレイアウトの一番上に置く人もいます)どういうわけか、オンデマンドでそれを表示/非表示にします)。

次に、RVに埋め込まれたSimpleExoPlayerViewからプレーヤーインスタンスをデタッチし、それを 静的ヘルパーメソッド への呼び出しでフルスクリーンビューにアタッチします。

SimpleExoPlayerView.switchTargetView(simpleExoPlayer, oldPlayerView, newPlayerView);

このアプローチは、API> = 23で非常にうまく機能します。 API 23では、メソッド MediaCodec.setOutputSurface が動的にサーフェスをスワップできるようになりました。上記の静的メソッドは、この手法が確実に適用されるようにします。その結果、オーディオとビデオは再生を続け、フルスクリーンに出入りするユーザーエクスペリエンスは非常にスムーズです。 API <= 22の場合、別のサーフェスにスワップするには、新しいコーデックインスタンスを作成する必要があります。これにより再生が中断され、このアプローチのユーザーエクスペリエンスが低下します。

アプローチ2

低いAPIレベルで別のサーフェスにスワップしないようにするには、単一のサーフェスを使用して、なんらかの方法でフルスクリーンに移行する必要があります。 SimpleExoPlayerView以外のすべてを非表示にして、レイアウトの幅と高さを親に一致するように設定するか、ビデオビューをプレースホルダーに置き換えて上下に配置することができます。

これは単純なレイアウトでは非常にうまく機能しますが、フラグメント、ビューページャー、リサイクラービューなどの複雑なレイアウトでは、非常に煩わしい操作になり、何かがちらついたり、再生がすぐに中断したりする可能性があります(たとえば、一部のAPIレベルでは、ビュー階層からプレーヤービューを削除する場合)。 )。これがさまざまなレイアウトでうまく機能するのを見てきました。

さらにアプローチ/課題

より深く掘り下げる場合や、SimpleExoPlayerViewをまったく使用しない場合は、他の、おそらくより優れたアプローチが考えられます。

11
marcbaechinger

FullScreen Exoplayerが必要な場合は、このライブラリを使用できます。

https://github.com/Norulab/Android-exoplayer-fullscreen

このライブラリには、ExoPlayerの拡張機能がいくつか含まれています。

val player = SimpleExoPlayer.Builder(context).build()
player.preparePlayer(playerView)
player.setSource(applicationContext, "http://html5videoformatconverter.com/data/images/happyfit2.mp4")
0
Jéwôm'

Exoplayerはフルスクリーンを提供しないので、ここで私のために働いた回避策があります。ここでは、画面の回転を制限し、方向を手動で変更して、player_viewの幅と高さをプログラムで変更し、ツールバーの表示を設定しました。データバインディングとKotlinを使用。

XMLのコードブロックに従います

<androidx.constraintlayout.widget.ConstraintLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        Android:id="@+id/video_player_container"
        Android:layout_width="match_parent"
        Android:layout_height="250dp"
        app:layout_constraintTop_toTopOf="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"
            Android:keepScreenOn="true"
            Android:padding="0dp"
            app:controller_layout_id="@layout/exo_playback_control_view"
            app:layout_constraintTop_toTopOf="parent"
            app:resize_mode="fill"
            app:use_controller="true" />

        <LinearLayout
            Android:id="@+id/nextVideoContainer"
            Android:layout_width="wrap_content"
            Android:layout_height="@dimen/spacing_32"
            Android:background="#90000000"
            Android:onClick="@{() -> vm.onNextVideo()}"
            Android:orientation="horizontal"
            Android:paddingLeft="@dimen/spacing_16"
            Android:paddingRight="@dimen/spacing_16"
            Android:visibility="@{vm.shouldShowNextBtn}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <com.sharedcode.widgets.CustomTextView
                Android:id="@+id/next_video_label"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_gravity="center_vertical"
                Android:text="@string/label_next"
                Android:textColor="@Android:color/white" />

            <com.sharedcode.widgets.CustomImageView
                Android:id="@+id/next_video_image"
                Android:layout_width="10dp"
                Android:layout_height="10dp"
                Android:layout_gravity="center_vertical"
                Android:layout_marginStart="8dp"
                Android:layout_marginLeft="8dp"
                Android:paddingTop="2dp"
                Android:src="@drawable/ic_play_next" />
        </LinearLayout>

        <RelativeLayout
            Android:id="@+id/retry_container"
            Android:layout_width="0dp"
            Android:layout_height="0dp"
            Android:background="#90000000"
            Android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            Android:onClick="@{() -> vm.onRetry()}">

            <com.sharedcode.widgets.CustomTextView
                Android:id="@+id/txt_no_internet"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_marginBottom="0dp"
                Android:layout_centerInParent="true"
                Android:text="@string/txt_no_internet_connection"
                Android:textColor="@Android:color/white"
                Android:textSize="@dimen/font_16" />

            <com.sharedcode.widgets.CustomTextView
                Android:layout_width="`wrap_content`"
                Android:layout_height="wrap_content"
                Android:layout_below="@+id/txt_no_internet"
                Android:layout_centerInParent="true"
                Android:layout_marginTop="@dimen/spacing_16"
                Android:maxHeight="@dimen/spacing_32"
                Android:text="@string/txt_tap_to_retry"
                Android:textColor="@Android:color/white"
                Android:textSize="@dimen/font_16" />


        </RelativeLayout>
     </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>

Androidマニフェストの変更

<activity Android:name=".yourPackage.ClassName"
        Android:screenOrientation="portrait"
        Android:configChanges="orientation|screenSize|layoutDirection"/>

向きを確認し、次のコードで回転させます

mBinding.playerView.exo_fullscreen_btn.setOnClickListener {
        if ((activity as TrainingVideoActivity).checkLandscapeOrientation()) {
            (activity as TrainingVideoActivity).changeOrientationToLandscape(false)

        } else {
            (activity as TrainingVideoActivity).changeOrientationToLandscape(true)

        }

    }

メソッドのシグネチャは次のとおりです

/**
 * Changes the Orientation
 * @param shouldLandscape
 */
fun changeOrientationToLandscape(shouldLandscape: Boolean) {
    requestedOrientation = if (shouldLandscape) {
        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
    } else {
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
    }
}

/**
 * Checks the Orientation
 * And returns true if Landscape else false
 */
fun checkLandscapeOrientation() : Boolean {
    val orientation = resources.configuration.orientation
    return orientation == Configuration.ORIENTATION_LANDSCAPE
}

ここでFragmentを使用しているため、フラグメント/アクティビティでonConfigurationChangedメソッドをオーバーライドするだけです。そこで、ExoplayerViewが配置される親コンテナーの幅/高さを変更しました。

/**
 * Used for Showing Video on Full Screen
 * @param newConfig
 * Used EXO_PLAYER_VIEW_HEIGHT as 250
 */
override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        hideToolbarAndShowFullScreen()
        mBinding.playerView.exo_fullscreen_btn.setImageDrawable(ContextCompat.getDrawable(activity!!, R.drawable.ic_shrink))
        val params = mBinding.videoPlayerContainer.layoutParams as ConstraintLayout.LayoutParams
        params.width = ViewGroup.LayoutParams.MATCH_PARENT
        params.height = ViewGroup.LayoutParams.MATCH_PARENT
        mBinding.videoPlayerContainer.layoutParams = params
    } else {
        showToolbarAndClearFullScreen()
        mBinding.playerView.exo_fullscreen_btn.setImageDrawable(ContextCompat.getDrawable(activity!!, R.drawable.ic_fullscreen))
        val params = mBinding.videoPlayerContainer.layoutParams as ConstraintLayout.LayoutParams
        val factor = mBinding.playerView.context.resources.displayMetrics.density
        params.width = ViewGroup.LayoutParams.MATCH_PARENT
        params.height = (EXO_PLAYER_VIEW_HEIGHT * factor).toInt()
        mBinding.videoPlayerContainer.layoutParams = params
    }
}

/**
 * Show the Toolbar and reset to original in the Portrait Mode
 */
private fun showToolbarAndClearFullScreen() {
    (activity as TrainingVideoActivity).supportActionBar!!.show()
    (activity as TrainingVideoActivity).window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)

}

最後に、player_controllerのXML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">

<RelativeLayout 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"
    Android:background="#99000000">


    <LinearLayout
        Android:id="@+id/container_play_pause"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_centerInParent="true"
        Android:orientation="horizontal">

        <ImageButton
            Android:id="@id/exo_play"
            style="@style/ExoMediaButton.Play"
            Android:src="@drawable/ic_play_exoplayer"
            />

        <ImageButton
            Android:id="@id/exo_pause"
            style="@style/ExoMediaButton.Pause"
            Android:src="@drawable/ic_pause_exoplayer"/>
    </LinearLayout>

    <LinearLayout
        Android:id="@+id/seekbar_bottom"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_alignParentBottom="true"
        Android:layout_gravity="bottom"
        Android:background="#CC000000"
        Android:clickable="false"
        Android:orientation="vertical">

        <LinearLayout
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:layout_marginTop="4dp"
            Android:gravity="center_vertical"
            Android:orientation="horizontal"
            tools:ignore="UselessParent">

            <com.sharedcode.widgets.CustomTextView
                Android:id="@id/exo_position"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:includeFontPadding="false"
                Android:paddingLeft="4dp"
                Android:paddingRight="4dp"
                Android:textColor="#FFBEBEBE"
                Android:textSize="14sp"
                Android:textStyle="bold" />

            <com.bnb.paynearby.utils.exoplayer.ExtendedTimebar
                Android:id="@id/exo_progress"
                Android:layout_width="0dp"
                Android:layout_height="50dp"
                Android:layout_weight="1"
                app:buffered_color="@color/white"
                app:played_color="@color/color_red"
                app:scrubber_color="@color/color_red"
                app:scrubber_disabled_size="10dp"
                app:unplayed_color="#484848" />

            <com.sharedcode.widgets.CustomTextView
                Android:id="@id/exo_duration"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:clickable="false"
                Android:includeFontPadding="false"
                Android:paddingLeft="4dp"
                Android:paddingRight="4dp"
                Android:textColor="#FFBEBEBE"
                Android:textSize="14sp"
                Android:textStyle="bold" />

            <com.sharedcode.widgets.CustomImageView
                Android:id="@+id/exo_fullscreen_btn"
                Android:layout_width="24dp"
                Android:layout_height="24dp"
                Android:layout_margin="8dp"
                Android:src="@drawable/ic_fullscreen"
                 />

        </LinearLayout>
    </LinearLayout>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

これが機能するかどうか教えてください。

0
Harsh Masand

必ず、親と一致するようにプレーヤービューの長さと幅を設定してください。

  1. これを使用してステータスバーを非表示にします:getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

  2. これを使用して、ナビゲーションバーを非表示にします。getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

0
NocTurn

プレーヤーのパラメーターを設定することで、プレーヤーを全画面に設定できます。

        Params params = (LinearLayout.LayoutParams) 
exoPlayerView.getLayoutParams();
        params.width=params.MATCH_PARENT;
        params.height=params.MATCH_PARENT;
        exoPlayerView.setLayoutParams(params);
    }

アクションバーを非表示にします。

 getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
 getActionBar().hide();

それが役に立てば幸い

0
Lior Michelzon