Skip to content

Conversation

mzhsy1
Copy link

@mzhsy1 mzhsy1 commented Oct 10, 2025

Summary

This PR introduces a new Jetpack Compose composable, SubtitleView, designed to render subtitles provided by Media3's CueGroup. It supports both text cues (e.g., SRT, SSA/ASS converted by ExoPlayer) and bitmap cues (e.g., PNG images), respecting their layout properties such as position, size, and anchor point.

The component is built using Material 3 guidelines and provides customizable styling for text subtitles, including text style and background color. It is intended for use within Compose-based media player UIs.

Features

  • Renders both text and bitmap cues from a CueGroup.
  • Supports positioning, sizing, and anchoring based on cue metadata.
  • Customizable TextStyle and background for text cues.
  • Aligns subtitle area to the bottom center by default.
  • Includes KDoc with usage example.

Example Usage

@Composable
fun VideoPlayerScreen(exoPlayer: ExoPlayer) {
  var currentCueGroup: CueGroup? by remember { mutableStateOf(null) }

  DisposableEffect(exoPlayer) {
    val listener = object : Player.Listener {
      override fun onCues(cueGroup: CueGroup) {
        currentCueGroup = cueGroup
      }
    }
    exoPlayer.addListener(listener)
    onDispose {
      exoPlayer.removeListener(listener)
    }
  }

  Box {
    // Your video surface or PlayerView here
     PlayerView()
     ......
    SubtitleView(
      cueGroup = currentCueGroup,
      subtitleStyle = MaterialTheme.typography.bodyLarge.copy(
        color = Color.White,
        fontSize = 20.sp
      ),
      backgroundColor = Color.Black.copy(alpha = 0.5f),
      modifier = Modifier.align(Alignment.BottomCenter)
    )
  }
}

Test

SRT Rendering

Screenshot_20251010_105207

PGS Rendering

  • Versus PlayerView's SubtitleView rendering
Screenshot_20251010_183308

@mzhsy1 mzhsy1 changed the title Add Compose-based SubtitleView for rendering CueGroup in Jetpack Compose Add Compose-based (Material 3) SubtitleView for rendering CueGroup in Jetpack Compose Oct 10, 2025
… in dp across devices with different DPIs (e.g., phones at 320 dpi, TVs at 240 dpi), ensuring PSG subtitles are correctly positioned.
@oceanjules
Copy link
Contributor

oceanjules commented Oct 13, 2025

Hi @mzhsy1,

Thank you for your contribution. I appreciate you taking the time to create this composable. Subtitles and Ads are important milestones for us to match the feature parity of Composables with PlayerView and they are quite big projects in themselves.

However, this pull request does not meet the standards required for merging into the library in its current state. Things like:

  • Use of magic numbers and hardcoded offsets
  • No tests
  • A lot of unsafe null handling
  • Unhandled accessibility
  • Unhandled device rotation and configuration changes

From the design perspective, we are unsure for now about going ahead with using Image() composables. In the View world, https://github.com/androidx/media/blob/release/libraries/ui/src/main/java/androidx/media3/ui/SubtitleView.java delegated to https://github.com/androidx/media/blob/release/libraries/ui/src/main/java/androidx/media3/ui/CanvasSubtitleOutput.java and https://github.com/androidx/media/blob/release/libraries/ui/src/main/java/androidx/media3/ui/WebViewSubtitleOutput.java. You can see how thorough and detailed those cases are and we would want to match that. Perhaps with using Canvas (import androidx.compose.foundation.Canvas) and AndroidView (androidx.compose.ui.viewinterop.AndroidView) for Webview interop - this way we could build a solution without relying on Material3 at all - but this hasn't been prioritised for the upcoming 1.9.0 release.

I suggest we park this PR until next quarter and revisit it next quarter when we will have more resources to dedicate to it.

@mzhsy1
Copy link
Author

mzhsy1 commented Oct 14, 2025

Thank you for your reply. This Compose component is part of my personal project, created to replace the SubtitleView in PlayerView. The built-in SubtitleView has two issues that don’t meet my needs: first, it displays PGS subtitles from certain Blu-ray disc rips with incorrect aspect ratios; second, when multiple SRT subtitle entries share the same timestamp, it only shows one of them.

This Compose component successfully addresses both issues and is currently working well in my project. However, it may fail to fully render PGS subtitles when too many images appear on screen simultaneously.

I’ve seen your suggestion to switch from Image()-based rendering to Canvas() rendering. Regarding the offset:

Modifier.offset(x = offsetX.dp - 14.dp, y = offsetY.dp - 8.dp)

This offset is used to correct the display position of PGS subtitles. At the moment, I’m not sure why these specific offset values are necessary during normal rendering—it just happens to fix the misalignment.

I’m currently experimenting in my personal project with migrating both Text() and Image() rendering to Canvas(). So far, I’ve completed the migration from Image() to Canvas(), but the subtitle positioning offset issue mentioned above still persists. I’ll continue refining the implementation and evaluate the results.

Thank you for your suggestion! For now, I won’t submit these changes to this PR. If you develop a better subtitle rendering solution, please release it as soon as possible—I’ll prioritize adopting it.

@icbaker
Copy link
Collaborator

icbaker commented Oct 14, 2025

Bit of a drive-by:

displays PGS subtitles from certain Blu-ray disc rips with incorrect aspect ratios

This sounds possibly similar to #2446 - which I think was resolved by ensuring the SubtitleView is nested inside AspectRationFrameLayout - I wonder if you're seeing a similar issue?

If it's not the same, please can you file a new issue with content we can use to repro the issue in the demo app and we can take a look.

@mzhsy1
Copy link
Author

mzhsy1 commented Oct 14, 2025

It seems that issue #2446 has not been resolved.
The one above is the default SubtitleView, and the subtitles below are from my custom SubtitleView.
Test video link: https://github.com/mzhsy1/MzDKPlayer/blob/main/demovideo/output%20(1).mkv 1min,10MB
MKV videos can't be uploaded in PRs, and PGS subtitles require the MKV format, so I've placed it in my personal repository.
Screenshot_20251015_000210
Screenshot_20251015_000319
Play it on PC using PotPlayer.
 2025-10-15 002257

@icbaker
Copy link
Collaborator

icbaker commented Oct 14, 2025

please can you file a new issue with content we can use to repro the issue in the demo app and we can take a look.

@mzhsy1
Copy link
Author

mzhsy1 commented Oct 15, 2025

please can you file a new issue with content we can use to repro the issue in the demo app and we can take a look.

@icbaker I have created an issue. #2849

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants