Merge branch 'adaptive-streaming-auto-ui' into 'master'

Auto mode UI for adaptive streams (HLS and DASH)

See merge request videostreaming/grayjay!76
This commit is contained in:
Kelvin 2025-02-10 18:47:50 +00:00
commit a01f3da66e
4 changed files with 63 additions and 19 deletions

View File

@ -171,7 +171,6 @@ import kotlinx.coroutines.withContext
import userpackage.Protocol import userpackage.Protocol
import java.time.OffsetDateTime import java.time.OffsetDateTime
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToLong import kotlin.math.roundToLong
@UnstableApi @UnstableApi
@ -1901,13 +1900,45 @@ class VideoDetailView : ConstraintLayout {
return super.onInterceptTouchEvent(ev); return super.onInterceptTouchEvent(ev);
} }
//Actions //Actions
private fun showVideoSettings() { private fun showVideoSettings() {
Logger.i(TAG, "showVideoSettings") Logger.i(TAG, "showVideoSettings")
_overlay_quality_selector?.selectOption("video", _lastVideoSource); _overlay_quality_selector?.selectOption("video", _lastVideoSource);
_overlay_quality_selector?.selectOption("audio", _lastAudioSource); _overlay_quality_selector?.selectOption("audio", _lastAudioSource);
_overlay_quality_selector?.selectOption("subtitles", _lastSubtitleSource); _overlay_quality_selector?.selectOption("subtitles", _lastSubtitleSource);
if (_lastVideoSource is IDashManifestSource || _lastVideoSource is IHLSManifestSource) {
val videoTracks =
_player.exoPlayer?.player?.currentTracks?.groups?.firstOrNull { it.mediaTrackGroup.type == C.TRACK_TYPE_VIDEO }
var selectedQuality: Format? = null
if (videoTracks != null) {
for (i in 0 until videoTracks.mediaTrackGroup.length) {
if (videoTracks.mediaTrackGroup.getFormat(i).height == _player.targetTrackVideoHeight) {
selectedQuality = videoTracks.mediaTrackGroup.getFormat(i)
}
}
}
var videoMenuGroup: SlideUpMenuGroup? = null
for (view in _overlay_quality_selector!!.groupItems) {
if (view is SlideUpMenuGroup && view.groupTag == "video") {
videoMenuGroup = view
}
}
if (selectedQuality != null) {
videoMenuGroup?.getItem("auto")?.setSubText("")
_overlay_quality_selector?.selectOption("video", selectedQuality)
} else {
videoMenuGroup?.getItem("auto")
?.setSubText("${_player.exoPlayer?.player?.videoFormat?.width}x${_player.exoPlayer?.player?.videoFormat?.height}")
_overlay_quality_selector?.selectOption("video", "auto")
}
}
val currentPlaybackRate = (if (_isCasting) StateCasting.instance.activeDevice?.speed else _player.getPlaybackRate()) ?: 1.0 val currentPlaybackRate = (if (_isCasting) StateCasting.instance.activeDevice?.speed else _player.getPlaybackRate()) ?: 1.0
_overlay_quality_selector?.groupItems?.firstOrNull { it is SlideUpMenuButtonList && it.id == "playback_rate" }?.let { _overlay_quality_selector?.groupItems?.firstOrNull { it is SlideUpMenuButtonList && it.id == "playback_rate" }?.let {
(it as SlideUpMenuButtonList).setSelected(currentPlaybackRate.toString()) (it as SlideUpMenuButtonList).setSelected(currentPlaybackRate.toString())
@ -2081,17 +2112,15 @@ class VideoDetailView : ConstraintLayout {
call = { handleSelectSubtitleTrack(it) }) call = { handleSelectSubtitleTrack(it) })
}.toList().toTypedArray()) }.toList().toTypedArray())
else null, else null,
if(liveStreamVideoFormats?.isEmpty() == false) if (liveStreamVideoFormats?.isEmpty() == false) SlideUpMenuGroup(
SlideUpMenuGroup(this.context, context.getString(R.string.stream_video), "video", this.context, context.getString(R.string.stream_video), "video", (listOf(
*liveStreamVideoFormats SlideUpMenuItem(this.context, R.drawable.ic_movie, "Auto", tag = "auto", call = { _player.selectVideoTrack(-1) })
.map { ) + (liveStreamVideoFormats.map {
SlideUpMenuItem(this.context, SlideUpMenuItem(this.context, R.drawable.ic_movie, it.label
R.drawable.ic_movie, ?: it.containerMimeType
it.label ?: it.containerMimeType ?: it.bitrate.toString(), ?: it.bitrate.toString(), "${it.width}x${it.height}", tag = it, call = { _player.selectVideoTrack(it.height) });
"${it.width}x${it.height}", }))
tag = it, )
call = { _player.selectVideoTrack(it.height) });
}.toList().toTypedArray())
else null, else null,
if(liveStreamAudioFormats?.isEmpty() == false) if(liveStreamAudioFormats?.isEmpty() == false)
SlideUpMenuGroup(this.context, context.getString(R.string.stream_audio), "audio", SlideUpMenuGroup(this.context, context.getString(R.string.stream_audio), "audio",

View File

@ -61,6 +61,15 @@ class SlideUpMenuGroup : LinearLayout {
return didSelect; return didSelect;
} }
fun getItem(tag: Any?): SlideUpMenuItem? {
for(item in items) {
if(item.itemTag == tag){
return item
}
}
return null
}
private fun addItems(items: List<SlideUpMenuItem>) { private fun addItems(items: List<SlideUpMenuItem>) {
for (item in items) { for (item in items) {
item.setParentClickListener { parentClickListener?.invoke() } item.setParentClickListener { parentClickListener?.invoke() }

View File

@ -82,6 +82,10 @@ class SlideUpMenuItem : ConstraintLayout {
return isSelected; return isSelected;
} }
fun setSubText(subText: String) {
_subtext.text = subText
}
fun setParentClickListener(listener: (()->Unit)?) { fun setParentClickListener(listener: (()->Unit)?) {
_parentClickListener = listener; _parentClickListener = listener;
} }

View File

@ -110,8 +110,10 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
private var _didCallSourceChange = false; private var _didCallSourceChange = false;
private var _lastState: Int = -1; private var _lastState: Int = -1;
private var _targetTrackVideoHeight = -1;
private var _targetTrackAudioBitrate = -1; var targetTrackVideoHeight = -1
private set
private var _targetTrackAudioBitrate = -1
private var _toResume = false; private var _toResume = false;
@ -278,7 +280,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
//TODO: Temporary solution, Implement custom track selector without using constraints //TODO: Temporary solution, Implement custom track selector without using constraints
fun selectVideoTrack(height: Int) { fun selectVideoTrack(height: Int) {
_targetTrackVideoHeight = height; targetTrackVideoHeight = height;
updateTrackSelector(); updateTrackSelector();
} }
fun selectAudioTrack(bitrate: Int) { fun selectAudioTrack(bitrate: Int) {
@ -288,10 +290,10 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun updateTrackSelector() { private fun updateTrackSelector() {
var builder = DefaultTrackSelector.Parameters.Builder(context); var builder = DefaultTrackSelector.Parameters.Builder(context);
if(_targetTrackVideoHeight > 0) { if(targetTrackVideoHeight > 0) {
builder = builder builder = builder
.setMinVideoSize(0, _targetTrackVideoHeight - 10) .setMinVideoSize(0, targetTrackVideoHeight - 10)
.setMaxVideoSize(9999, _targetTrackVideoHeight + 10); .setMaxVideoSize(9999, targetTrackVideoHeight + 10);
} }
if(_targetTrackAudioBitrate > 0) { if(_targetTrackAudioBitrate > 0) {