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.Handler
import android.os.Looper import android.os.Looper
import android.view.KeyEvent import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.focusable import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@ -58,6 +60,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.jeena.jtubetv.AppGraph import net.jeena.jtubetv.AppGraph
import net.jeena.jtubetv.R
import net.jeena.jtubetv.data.PeerTubeRepository import net.jeena.jtubetv.data.PeerTubeRepository
import net.jeena.jtubetv.data.api.VideoDetailDto import net.jeena.jtubetv.data.api.VideoDetailDto
import net.jeena.jtubetv.data.auth.TokenStore import net.jeena.jtubetv.data.auth.TokenStore
@ -366,8 +369,13 @@ private fun PlayerSurface(
) { ) {
AndroidView( AndroidView(
factory = { ctx -> 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 useController = true
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
this.player = player this.player = player
isFocusable = false isFocusable = false
descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS 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" />