mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-16 02:44:51 +00:00
fix(exoplayer): properly handle aspect ratio & subtitles
This commit is contained in:
@@ -4,6 +4,7 @@ import android.app.PictureInPictureParams
|
|||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Rational
|
import android.util.Rational
|
||||||
|
import android.view.Gravity
|
||||||
import android.view.SurfaceHolder
|
import android.view.SurfaceHolder
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -11,6 +12,10 @@ import android.view.ViewGroup
|
|||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.VideoSize
|
||||||
|
import androidx.media3.common.text.CueGroup
|
||||||
|
import androidx.media3.ui.AspectRatioFrameLayout
|
||||||
|
import androidx.media3.ui.SubtitleView
|
||||||
import com.facebook.react.bridge.LifecycleEventListener
|
import com.facebook.react.bridge.LifecycleEventListener
|
||||||
import com.facebook.react.uimanager.ThemedReactContext
|
import com.facebook.react.uimanager.ThemedReactContext
|
||||||
import com.margelo.nitro.omni.HybridOmniPlayerSpec
|
import com.margelo.nitro.omni.HybridOmniPlayerSpec
|
||||||
@@ -68,6 +73,16 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val contentFrame = AspectRatioFrameLayout(context).apply {
|
||||||
|
setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT)
|
||||||
|
layoutParams = FrameLayout.LayoutParams(
|
||||||
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
Gravity.CENTER
|
||||||
|
)
|
||||||
|
view.addView(this)
|
||||||
|
}
|
||||||
|
|
||||||
private val surfaceView = SurfaceView(context).apply {
|
private val surfaceView = SurfaceView(context).apply {
|
||||||
layoutParams = FrameLayout.LayoutParams(
|
layoutParams = FrameLayout.LayoutParams(
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
@@ -75,8 +90,19 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
)
|
)
|
||||||
holder.addCallback(this@OmniView)
|
holder.addCallback(this@OmniView)
|
||||||
addOnLayoutChangeListener(this@OmniView)
|
addOnLayoutChangeListener(this@OmniView)
|
||||||
|
contentFrame.addView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val subtitleView = SubtitleView(context).apply {
|
||||||
|
layoutParams = FrameLayout.LayoutParams(
|
||||||
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
|
)
|
||||||
|
setUserDefaultStyle()
|
||||||
|
setUserDefaultTextSize()
|
||||||
view.addView(this)
|
view.addView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var surfaceReady = false
|
private var surfaceReady = false
|
||||||
private var boundPlayer: OmniPlayer? = null
|
private var boundPlayer: OmniPlayer? = null
|
||||||
private var rootContent: ViewGroup? = null
|
private var rootContent: ViewGroup? = null
|
||||||
@@ -94,6 +120,20 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
context.addLifecycleEventListener(this)
|
context.addLifecycleEventListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||||
|
contentFrame.setAspectRatio(
|
||||||
|
if (videoSize.width > 0 && videoSize.height > 0) {
|
||||||
|
videoSize.width * videoSize.pixelWidthHeightRatio / videoSize.height
|
||||||
|
} else {
|
||||||
|
0f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCues(cueGroup: CueGroup) {
|
||||||
|
subtitleView.setCues(cueGroup.cues)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onLayoutChange(
|
override fun onLayoutChange(
|
||||||
view: View?,
|
view: View?,
|
||||||
left: Int,
|
left: Int,
|
||||||
@@ -307,7 +347,7 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
child.visibility = View.GONE
|
child.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
view.removeView(surfaceView)
|
contentFrame.removeView(surfaceView)
|
||||||
root.addView(
|
root.addView(
|
||||||
surfaceView,
|
surfaceView,
|
||||||
FrameLayout.LayoutParams(
|
FrameLayout.LayoutParams(
|
||||||
@@ -331,7 +371,7 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
}
|
}
|
||||||
rootContentViews = emptyList()
|
rootContentViews = emptyList()
|
||||||
|
|
||||||
view.addView(surfaceView, FrameLayout.LayoutParams(
|
contentFrame.addView(surfaceView, FrameLayout.LayoutParams(
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT
|
FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -525,36 +525,43 @@ class VlcPlayer(ctx: Context) :
|
|||||||
val selectedAudio = player.getSelectedTrack(IMedia.Track.Type.Audio)
|
val selectedAudio = player.getSelectedTrack(IMedia.Track.Type.Audio)
|
||||||
val selectedSubtitle = player.getSelectedTrack(IMedia.Track.Type.Text)
|
val selectedSubtitle = player.getSelectedTrack(IMedia.Track.Type.Text)
|
||||||
|
|
||||||
val videoTracks = player.getTracks(IMedia.Track.Type.Video)
|
player.getTracks(IMedia.Track.Type.Video).orEmpty()
|
||||||
if (!videoTracks.isNullOrEmpty()) {
|
.groupBy { listOf(it.language, it.name, it.description) }
|
||||||
val videoFormats = videoTracks.map { track ->
|
.values.forEach { videoTracks ->
|
||||||
Format.Builder()
|
val videoFormats = videoTracks.map { track ->
|
||||||
.setId(track.id)
|
Format.Builder()
|
||||||
.setLabel(track.name)
|
.setId(track.id)
|
||||||
.setLanguage(track.language)
|
.setLabel(track.name)
|
||||||
.setSampleMimeType("video/x-unknown")
|
.setLanguage(track.language)
|
||||||
.build()
|
.setSampleMimeType("video/x-unknown")
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
val group = TrackGroup("vlc-video-${videoTracks.minOf { it.id }}", *videoFormats.toTypedArray())
|
||||||
|
val selected = BooleanArray(videoFormats.size) { idx ->
|
||||||
|
selectedVideo != null && selectedVideo.id == videoTracks[idx].id
|
||||||
|
}
|
||||||
|
val support = IntArray(videoFormats.size) { FORMAT_HANDLED }
|
||||||
|
result.add(Group(group, videoFormats.size > 1, support, selected))
|
||||||
}
|
}
|
||||||
val group = TrackGroup("vlc-video", *videoFormats.toTypedArray())
|
|
||||||
val selected = BooleanArray(videoFormats.size) { idx ->
|
|
||||||
selectedVideo != null && selectedVideo.id == videoTracks[idx].id
|
|
||||||
}
|
|
||||||
val support = IntArray(videoFormats.size) { FORMAT_HANDLED }
|
|
||||||
result.add(Group(group, videoFormats.size > 1, support, selected))
|
|
||||||
}
|
|
||||||
|
|
||||||
player.getTracks(IMedia.Track.Type.Audio)?.forEach { track ->
|
player.getTracks(IMedia.Track.Type.Audio).orEmpty()
|
||||||
val format = Format.Builder()
|
.groupBy { listOf(it.language, it.name, it.description) }
|
||||||
.setId(track.id)
|
.values.forEach { audioTracks ->
|
||||||
.setLabel(track.name)
|
val audioFormats = audioTracks.map { track ->
|
||||||
.setLanguage(track.language)
|
Format.Builder()
|
||||||
.setSampleMimeType("audio/x-unknown")
|
.setId(track.id)
|
||||||
.build()
|
.setLabel(track.name)
|
||||||
val group = TrackGroup("vlc-audio-${track.id}", format)
|
.setLanguage(track.language)
|
||||||
val selected = booleanArrayOf(selectedAudio != null && selectedAudio.id == track.id)
|
.setSampleMimeType("audio/x-unknown")
|
||||||
val support = intArrayOf(FORMAT_HANDLED)
|
.build()
|
||||||
result.add(Group(group, false, support, selected))
|
}
|
||||||
}
|
val group = TrackGroup("vlc-audio-${audioTracks.minOf { it.id }}", *audioFormats.toTypedArray())
|
||||||
|
val selected = BooleanArray(audioFormats.size) { idx ->
|
||||||
|
selectedAudio != null && selectedAudio.id == audioTracks[idx].id
|
||||||
|
}
|
||||||
|
val support = IntArray(audioFormats.size) { FORMAT_HANDLED }
|
||||||
|
result.add(Group(group, audioFormats.size > 1, support, selected))
|
||||||
|
}
|
||||||
|
|
||||||
player.getTracks(IMedia.Track.Type.Text)?.forEach { track ->
|
player.getTracks(IMedia.Track.Type.Text)?.forEach { track ->
|
||||||
val format = Format.Builder()
|
val format = Format.Builder()
|
||||||
|
|||||||
Reference in New Issue
Block a user