player: Fix vertical videos stretched to full screen

On the HiMedia/Amlogic TV the video renders through the vendor video
plane, which scales the decoded stream to the whole panel and ignores
the letterbox geometry AspectRatioFrameLayout lays out for the
SurfaceView. Portrait videos therefore filled the screen instead of
being letterboxed; on emulators the same code was correct.

Render the video in a TextureView instead: it lives in the normal
view tree, so the aspect ratio is honored on every device. Verified
on the HiMedia box (vertical short letterboxed, landscape fills the
screen as before) and on the emulator.

Closes #1
This commit is contained in:
Jeena 2026-10-12 02:48:11 +00:00
parent 116b6926e4
commit 344a211d72
2 changed files with 22 additions and 1 deletions

View file

@ -4,9 +4,11 @@ import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
@ -58,6 +60,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import net.jeena.jtubetv.AppGraph
import net.jeena.jtubetv.R
import net.jeena.jtubetv.data.PeerTubeRepository
import net.jeena.jtubetv.data.api.VideoDetailDto
import net.jeena.jtubetv.data.auth.TokenStore
@ -366,8 +369,13 @@ private fun PlayerSurface(
) {
AndroidView(
factory = { ctx ->
PlayerView(ctx).apply {
// TextureView surface (layout file): SurfaceView goes through the
// vendor video plane on Amlogic boxes and gets stretched full
// screen regardless of the letterbox geometry (issue #1).
(LayoutInflater.from(ctx)
.inflate(R.layout.player_video_view, null) as PlayerView).apply {
useController = true
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
this.player = player
isFocusable = false
descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Player view with a TextureView surface: SurfaceView is routed through the
vendor video plane on some TV SoCs (Amlogic/HiMedia), which scales the
decoded video to the whole panel and ignores the letterbox geometry that
AspectRatioFrameLayout sets up, so portrait videos end up stretched full
screen. A TextureView renders in the normal view tree and honors the
aspect ratio everywhere (git issue #1). -->
<androidx.media3.ui.PlayerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:surface_type="texture_view" />